about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/anthropic
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/anthropic
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/anthropic')
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/__init__.py106
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_base_client.py2153
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_client.py531
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_compat.py219
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_constants.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_decoders/jsonl.py123
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_exceptions.py126
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_files.py123
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_legacy_response.py511
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_models.py832
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_qs.py150
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_resource.py41
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_response.py872
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_streaming.py443
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_types.py219
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/__init__.py57
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_logs.py25
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_proxy.py62
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_reflection.py42
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_streams.py12
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_sync.py86
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_transform.py402
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_typing.py149
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_utils/_utils.py414
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/_version.py4
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/.keep4
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/_extras/__init__.py1
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_common.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_google_auth.py29
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/__init__.py1
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_auth.py72
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta.py102
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta_messages.py93
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_client.py390
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream.py37
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream_decoder.py64
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/streaming/__init__.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_messages.py462
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_types.py100
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_messages.py462
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_types.py100
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/vertex/__init__.py1
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_auth.py42
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta.py102
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta_messages.py93
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_client.py406
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/pagination.py84
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/py.typed0
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/__init__.py61
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/beta/__init__.py47
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/beta/beta.py134
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/__init__.py33
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/batches.py889
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/messages.py2587
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/beta/models.py300
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/completions.py823
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/messages/__init__.py35
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/messages/batches.py717
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/messages/messages.py2551
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/resources/models.py300
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/__init__.py107
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/anthropic_beta_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/base64_image_source_param.py23
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/base64_pdf_source_param.py23
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/__init__.py76
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_image_source_param.py23
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_block_param.py33
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_source_param.py23
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_cache_control_ephemeral_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_config_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_delta.py23
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block.py17
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_param.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_content_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_param.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_image_block_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_input_json_delta.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message.py112
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_delta_usage.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_param.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_tokens_count.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_metadata_param.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_model_info.py28
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_plain_text_source_param.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_delta_event.py27
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_start_event.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_stop_event.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_delta_event.py39
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_start_event.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stop_event.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stream_event.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_signature_delta.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block.py23
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block_param.py21
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation_param.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_delta.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block_param.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_disabled_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_enabled_param.py24
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_delta.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20241022_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20250124_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_any_param.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_auto_param.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_none_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_param.py17
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_tool_param.py21
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20241022_param.py31
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20250124_param.py31
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_param.py47
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_result_block_param.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20241022_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20250124_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_union_param.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block.py17
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_image_source_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_pdf_source_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_usage.py21
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/message_count_tokens_params.py234
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/message_create_params.py297
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/__init__.py17
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_create_params.py41
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_list_params.py34
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_deleted_message_batch.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch.py77
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_canceled_result.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_errored_result.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_expired_result.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_individual_response.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_request_counts.py35
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_result.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_succeeded_result.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta/model_list_params.py27
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_api_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_authentication_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_billing_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_error.py32
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_error_response.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_gateway_timeout_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_invalid_request_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_not_found_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_overloaded_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_permission_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/beta_rate_limit_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/cache_control_ephemeral_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citations_config_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/citations_delta.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/completion.py43
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/completion_create_params.py131
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/content_block.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/content_block_delta_event.py9
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/content_block_param.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_content_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_param.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/content_block_start_event.py9
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/content_block_stop_event.py9
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/document_block_param.py31
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/image_block_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/input_json_delta.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message.py112
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_params.py212
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_tool_param.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_create_params.py320
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_delta_event.py9
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_delta_usage.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_param.py39
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_start_event.py9
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_stop_event.py9
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_stream_event.py9
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/message_tokens_count.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/__init__.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_create_params.py36
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_list_params.py27
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/deleted_message_batch.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch.py77
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_canceled_result.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_errored_result.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_expired_result.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_individual_response.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_request_counts.py35
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_result.py19
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_succeeded_result.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/metadata_param.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/model.py25
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/model_info.py28
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/model_list_params.py27
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/model_param.py27
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/plain_text_source_param.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_delta_event.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_start_event.py25
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_stop_event.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/raw_message_delta_event.py39
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/raw_message_start_event.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stop_event.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stream_event.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/__init__.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/api_error_object.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/authentication_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/billing_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/error_object.py32
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/error_response.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/gateway_timeout_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/invalid_request_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/not_found_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/overloaded_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/permission_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/shared/rate_limit_error.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/signature_delta.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/text_block.py23
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/text_block_param.py21
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/text_citation.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/text_citation_param.py16
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/text_delta.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/thinking_block.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/thinking_block_param.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_disabled_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_enabled_param.py24
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/thinking_delta.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_bash_20250124_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_any_param.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_auto_param.py18
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_none_param.py11
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_param.py15
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_tool_param.py21
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_param.py48
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_result_block_param.py26
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_text_editor_20250124_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_union_param.py14
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block.py17
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block_param.py22
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/url_image_source_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/url_pdf_source_param.py13
-rw-r--r--.venv/lib/python3.12/site-packages/anthropic/types/usage.py21
255 files changed, 24112 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/anthropic/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/__init__.py
new file mode 100644
index 00000000..8cba2f09
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/__init__.py
@@ -0,0 +1,106 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from . import types
+from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes
+from ._utils import file_from_path
+from ._client import (
+    Client,
+    Stream,
+    Timeout,
+    Anthropic,
+    Transport,
+    AsyncClient,
+    AsyncStream,
+    AsyncAnthropic,
+    RequestOptions,
+)
+from ._models import BaseModel
+from ._version import __title__, __version__
+from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse
+from ._constants import (
+    AI_PROMPT as AI_PROMPT,
+    HUMAN_PROMPT as HUMAN_PROMPT,
+    DEFAULT_TIMEOUT,
+    DEFAULT_MAX_RETRIES,
+    DEFAULT_CONNECTION_LIMITS,
+)
+from ._exceptions import (
+    APIError,
+    ConflictError,
+    NotFoundError,
+    AnthropicError,
+    APIStatusError,
+    RateLimitError,
+    APITimeoutError,
+    BadRequestError,
+    APIConnectionError,
+    AuthenticationError,
+    InternalServerError,
+    PermissionDeniedError,
+    UnprocessableEntityError,
+    APIResponseValidationError,
+)
+from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
+from ._utils._logs import setup_logging as _setup_logging
+
+__all__ = [
+    "types",
+    "__version__",
+    "__title__",
+    "NoneType",
+    "Transport",
+    "ProxiesTypes",
+    "NotGiven",
+    "NOT_GIVEN",
+    "Omit",
+    "AnthropicError",
+    "APIError",
+    "APIStatusError",
+    "APITimeoutError",
+    "APIConnectionError",
+    "APIResponseValidationError",
+    "BadRequestError",
+    "AuthenticationError",
+    "PermissionDeniedError",
+    "NotFoundError",
+    "ConflictError",
+    "UnprocessableEntityError",
+    "RateLimitError",
+    "InternalServerError",
+    "Timeout",
+    "RequestOptions",
+    "Client",
+    "AsyncClient",
+    "Stream",
+    "AsyncStream",
+    "Anthropic",
+    "AsyncAnthropic",
+    "file_from_path",
+    "BaseModel",
+    "DEFAULT_TIMEOUT",
+    "DEFAULT_MAX_RETRIES",
+    "DEFAULT_CONNECTION_LIMITS",
+    "DefaultHttpxClient",
+    "DefaultAsyncHttpxClient",
+    "HUMAN_PROMPT",
+    "AI_PROMPT",
+]
+
+from .lib.vertex import *
+from .lib.bedrock import *
+from .lib.streaming import *
+
+_setup_logging()
+
+# Update the __module__ attribute for exported symbols so that
+# error messages point to this module instead of the module
+# it was originally defined in, e.g.
+# anthropic._exceptions.NotFoundError -> anthropic.NotFoundError
+__locals = locals()
+for __name in __all__:
+    if not __name.startswith("__"):
+        try:
+            __locals[__name].__module__ = "anthropic"
+        except (TypeError, AttributeError):
+            # Some of our exported symbols are builtins which we can't set attributes for.
+            pass
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_base_client.py b/.venv/lib/python3.12/site-packages/anthropic/_base_client.py
new file mode 100644
index 00000000..41b57e18
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_base_client.py
@@ -0,0 +1,2153 @@
+from __future__ import annotations
+
+import sys
+import json
+import time
+import uuid
+import email
+import socket
+import asyncio
+import inspect
+import logging
+import platform
+import warnings
+import email.utils
+from types import TracebackType
+from random import random
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    Dict,
+    Type,
+    Union,
+    Generic,
+    Mapping,
+    TypeVar,
+    Iterable,
+    Iterator,
+    Optional,
+    Generator,
+    AsyncIterator,
+    cast,
+    overload,
+)
+from typing_extensions import Literal, override, get_origin
+
+import anyio
+import httpx
+import distro
+import pydantic
+from httpx import URL, Limits
+from pydantic import PrivateAttr
+
+from . import _exceptions
+from ._qs import Querystring
+from ._files import to_httpx_files, async_to_httpx_files
+from ._types import (
+    NOT_GIVEN,
+    Body,
+    Omit,
+    Query,
+    Headers,
+    Timeout,
+    NotGiven,
+    ResponseT,
+    Transport,
+    AnyMapping,
+    PostParser,
+    ProxiesTypes,
+    RequestFiles,
+    HttpxSendArgs,
+    AsyncTransport,
+    RequestOptions,
+    HttpxRequestFiles,
+    ModelBuilderProtocol,
+)
+from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
+from ._compat import PYDANTIC_V2, model_copy, model_dump
+from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type
+from ._response import (
+    APIResponse,
+    BaseAPIResponse,
+    AsyncAPIResponse,
+    extract_response_type,
+)
+from ._constants import (
+    DEFAULT_TIMEOUT,
+    MAX_RETRY_DELAY,
+    DEFAULT_MAX_RETRIES,
+    INITIAL_RETRY_DELAY,
+    RAW_RESPONSE_HEADER,
+    OVERRIDE_CAST_TO_HEADER,
+    DEFAULT_CONNECTION_LIMITS,
+)
+from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder
+from ._exceptions import (
+    APIStatusError,
+    APITimeoutError,
+    APIConnectionError,
+    APIResponseValidationError,
+)
+from ._legacy_response import LegacyAPIResponse
+
+log: logging.Logger = logging.getLogger(__name__)
+
+# TODO: make base page type vars covariant
+SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]")
+AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]")
+
+
+_T = TypeVar("_T")
+_T_co = TypeVar("_T_co", covariant=True)
+
+_StreamT = TypeVar("_StreamT", bound=Stream[Any])
+_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any])
+
+if TYPE_CHECKING:
+    from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT
+else:
+    try:
+        from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT
+    except ImportError:
+        # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366
+        HTTPX_DEFAULT_TIMEOUT = Timeout(5.0)
+
+
+class PageInfo:
+    """Stores the necessary information to build the request to retrieve the next page.
+
+    Either `url` or `params` must be set.
+    """
+
+    url: URL | NotGiven
+    params: Query | NotGiven
+
+    @overload
+    def __init__(
+        self,
+        *,
+        url: URL,
+    ) -> None: ...
+
+    @overload
+    def __init__(
+        self,
+        *,
+        params: Query,
+    ) -> None: ...
+
+    def __init__(
+        self,
+        *,
+        url: URL | NotGiven = NOT_GIVEN,
+        params: Query | NotGiven = NOT_GIVEN,
+    ) -> None:
+        self.url = url
+        self.params = params
+
+    @override
+    def __repr__(self) -> str:
+        if self.url:
+            return f"{self.__class__.__name__}(url={self.url})"
+        return f"{self.__class__.__name__}(params={self.params})"
+
+
+class BasePage(GenericModel, Generic[_T]):
+    """
+    Defines the core interface for pagination.
+
+    Type Args:
+        ModelT: The pydantic model that represents an item in the response.
+
+    Methods:
+        has_next_page(): Check if there is another page available
+        next_page_info(): Get the necessary information to make a request for the next page
+    """
+
+    _options: FinalRequestOptions = PrivateAttr()
+    _model: Type[_T] = PrivateAttr()
+
+    def has_next_page(self) -> bool:
+        items = self._get_page_items()
+        if not items:
+            return False
+        return self.next_page_info() is not None
+
+    def next_page_info(self) -> Optional[PageInfo]: ...
+
+    def _get_page_items(self) -> Iterable[_T]:  # type: ignore[empty-body]
+        ...
+
+    def _params_from_url(self, url: URL) -> httpx.QueryParams:
+        # TODO: do we have to preprocess params here?
+        return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params)
+
+    def _info_to_options(self, info: PageInfo) -> FinalRequestOptions:
+        options = model_copy(self._options)
+        options._strip_raw_response_header()
+
+        if not isinstance(info.params, NotGiven):
+            options.params = {**options.params, **info.params}
+            return options
+
+        if not isinstance(info.url, NotGiven):
+            params = self._params_from_url(info.url)
+            url = info.url.copy_with(params=params)
+            options.params = dict(url.params)
+            options.url = str(url)
+            return options
+
+        raise ValueError("Unexpected PageInfo state")
+
+
+class BaseSyncPage(BasePage[_T], Generic[_T]):
+    _client: SyncAPIClient = pydantic.PrivateAttr()
+
+    def _set_private_attributes(
+        self,
+        client: SyncAPIClient,
+        model: Type[_T],
+        options: FinalRequestOptions,
+    ) -> None:
+        if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
+            self.__pydantic_private__ = {}
+
+        self._model = model
+        self._client = client
+        self._options = options
+
+    # Pydantic uses a custom `__iter__` method to support casting BaseModels
+    # to dictionaries. e.g. dict(model).
+    # As we want to support `for item in page`, this is inherently incompatible
+    # with the default pydantic behaviour. It is not possible to support both
+    # use cases at once. Fortunately, this is not a big deal as all other pydantic
+    # methods should continue to work as expected as there is an alternative method
+    # to cast a model to a dictionary, model.dict(), which is used internally
+    # by pydantic.
+    def __iter__(self) -> Iterator[_T]:  # type: ignore
+        for page in self.iter_pages():
+            for item in page._get_page_items():
+                yield item
+
+    def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]:
+        page = self
+        while True:
+            yield page
+            if page.has_next_page():
+                page = page.get_next_page()
+            else:
+                return
+
+    def get_next_page(self: SyncPageT) -> SyncPageT:
+        info = self.next_page_info()
+        if not info:
+            raise RuntimeError(
+                "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`."
+            )
+
+        options = self._info_to_options(info)
+        return self._client._request_api_list(self._model, page=self.__class__, options=options)
+
+
+class AsyncPaginator(Generic[_T, AsyncPageT]):
+    def __init__(
+        self,
+        client: AsyncAPIClient,
+        options: FinalRequestOptions,
+        page_cls: Type[AsyncPageT],
+        model: Type[_T],
+    ) -> None:
+        self._model = model
+        self._client = client
+        self._options = options
+        self._page_cls = page_cls
+
+    def __await__(self) -> Generator[Any, None, AsyncPageT]:
+        return self._get_page().__await__()
+
+    async def _get_page(self) -> AsyncPageT:
+        def _parser(resp: AsyncPageT) -> AsyncPageT:
+            resp._set_private_attributes(
+                model=self._model,
+                options=self._options,
+                client=self._client,
+            )
+            return resp
+
+        self._options.post_parser = _parser
+
+        return await self._client.request(self._page_cls, self._options)
+
+    async def __aiter__(self) -> AsyncIterator[_T]:
+        # https://github.com/microsoft/pyright/issues/3464
+        page = cast(
+            AsyncPageT,
+            await self,  # type: ignore
+        )
+        async for item in page:
+            yield item
+
+
+class BaseAsyncPage(BasePage[_T], Generic[_T]):
+    _client: AsyncAPIClient = pydantic.PrivateAttr()
+
+    def _set_private_attributes(
+        self,
+        model: Type[_T],
+        client: AsyncAPIClient,
+        options: FinalRequestOptions,
+    ) -> None:
+        if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
+            self.__pydantic_private__ = {}
+
+        self._model = model
+        self._client = client
+        self._options = options
+
+    async def __aiter__(self) -> AsyncIterator[_T]:
+        async for page in self.iter_pages():
+            for item in page._get_page_items():
+                yield item
+
+    async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]:
+        page = self
+        while True:
+            yield page
+            if page.has_next_page():
+                page = await page.get_next_page()
+            else:
+                return
+
+    async def get_next_page(self: AsyncPageT) -> AsyncPageT:
+        info = self.next_page_info()
+        if not info:
+            raise RuntimeError(
+                "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`."
+            )
+
+        options = self._info_to_options(info)
+        return await self._client._request_api_list(self._model, page=self.__class__, options=options)
+
+
+_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient])
+_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]])
+
+
+class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
+    _client: _HttpxClientT
+    _version: str
+    _base_url: URL
+    max_retries: int
+    timeout: Union[float, Timeout, None]
+    _limits: httpx.Limits
+    _proxies: ProxiesTypes | None
+    _transport: Transport | AsyncTransport | None
+    _strict_response_validation: bool
+    _idempotency_header: str | None
+    _default_stream_cls: type[_DefaultStreamT] | None = None
+
+    def __init__(
+        self,
+        *,
+        version: str,
+        base_url: str | URL,
+        _strict_response_validation: bool,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        timeout: float | Timeout | None = DEFAULT_TIMEOUT,
+        limits: httpx.Limits,
+        transport: Transport | AsyncTransport | None,
+        proxies: ProxiesTypes | None,
+        custom_headers: Mapping[str, str] | None = None,
+        custom_query: Mapping[str, object] | None = None,
+    ) -> None:
+        self._version = version
+        self._base_url = self._enforce_trailing_slash(URL(base_url))
+        self.max_retries = max_retries
+        self.timeout = timeout
+        self._limits = limits
+        self._proxies = proxies
+        self._transport = transport
+        self._custom_headers = custom_headers or {}
+        self._custom_query = custom_query or {}
+        self._strict_response_validation = _strict_response_validation
+        self._idempotency_header = None
+        self._platform: Platform | None = None
+
+        if max_retries is None:  # pyright: ignore[reportUnnecessaryComparison]
+            raise TypeError(
+                "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `anthropic.DEFAULT_MAX_RETRIES`"
+            )
+
+    def _enforce_trailing_slash(self, url: URL) -> URL:
+        if url.raw_path.endswith(b"/"):
+            return url
+        return url.copy_with(raw_path=url.raw_path + b"/")
+
+    def _make_status_error_from_response(
+        self,
+        response: httpx.Response,
+    ) -> APIStatusError:
+        if response.is_closed and not response.is_stream_consumed:
+            # We can't read the response body as it has been closed
+            # before it was read. This can happen if an event hook
+            # raises a status error.
+            body = None
+            err_msg = f"Error code: {response.status_code}"
+        else:
+            err_text = response.text.strip()
+            body = err_text
+
+            try:
+                body = json.loads(err_text)
+                err_msg = f"Error code: {response.status_code} - {body}"
+            except Exception:
+                err_msg = err_text or f"Error code: {response.status_code}"
+
+        return self._make_status_error(err_msg, body=body, response=response)
+
+    def _make_status_error(
+        self,
+        err_msg: str,
+        *,
+        body: object,
+        response: httpx.Response,
+    ) -> _exceptions.APIStatusError:
+        raise NotImplementedError()
+
+    def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers:
+        custom_headers = options.headers or {}
+        headers_dict = _merge_mappings(
+            {
+                "x-stainless-timeout": str(options.timeout.read)
+                if isinstance(options.timeout, Timeout)
+                else str(options.timeout),
+                **self.default_headers,
+            },
+            custom_headers,
+        )
+        self._validate_headers(headers_dict, custom_headers)
+
+        # headers are case-insensitive while dictionaries are not.
+        headers = httpx.Headers(headers_dict)
+
+        idempotency_header = self._idempotency_header
+        if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers:
+            headers[idempotency_header] = options.idempotency_key or self._idempotency_key()
+
+        # Don't set these headers if they were already set or removed by the caller. We check
+        # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case.
+        lower_custom_headers = [header.lower() for header in custom_headers]
+        if "x-stainless-retry-count" not in lower_custom_headers:
+            headers["x-stainless-retry-count"] = str(retries_taken)
+        if "x-stainless-read-timeout" not in lower_custom_headers:
+            timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout
+            if isinstance(timeout, Timeout):
+                timeout = timeout.read
+            if timeout is not None:
+                headers["x-stainless-read-timeout"] = str(timeout)
+
+        return headers
+
+    def _prepare_url(self, url: str) -> URL:
+        """
+        Merge a URL argument together with any 'base_url' on the client,
+        to create the URL used for the outgoing request.
+        """
+        # Copied from httpx's `_merge_url` method.
+        merge_url = URL(url)
+        if merge_url.is_relative_url:
+            merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/")
+            return self.base_url.copy_with(raw_path=merge_raw_path)
+
+        return merge_url
+
+    def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder:
+        return SSEDecoder()
+
+    def _build_request(
+        self,
+        options: FinalRequestOptions,
+        *,
+        retries_taken: int = 0,
+    ) -> httpx.Request:
+        if log.isEnabledFor(logging.DEBUG):
+            log.debug("Request options: %s", model_dump(options, exclude_unset=True))
+
+        kwargs: dict[str, Any] = {}
+
+        json_data = options.json_data
+        if options.extra_json is not None:
+            if json_data is None:
+                json_data = cast(Body, options.extra_json)
+            elif is_mapping(json_data):
+                json_data = _merge_mappings(json_data, options.extra_json)
+            else:
+                raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`")
+
+        headers = self._build_headers(options, retries_taken=retries_taken)
+        params = _merge_mappings(self.default_query, options.params)
+        content_type = headers.get("Content-Type")
+        files = options.files
+
+        # If the given Content-Type header is multipart/form-data then it
+        # has to be removed so that httpx can generate the header with
+        # additional information for us as it has to be in this form
+        # for the server to be able to correctly parse the request:
+        # multipart/form-data; boundary=---abc--
+        if content_type is not None and content_type.startswith("multipart/form-data"):
+            if "boundary" not in content_type:
+                # only remove the header if the boundary hasn't been explicitly set
+                # as the caller doesn't want httpx to come up with their own boundary
+                headers.pop("Content-Type")
+
+            # As we are now sending multipart/form-data instead of application/json
+            # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding
+            if json_data:
+                if not is_dict(json_data):
+                    raise TypeError(
+                        f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead."
+                    )
+                kwargs["data"] = self._serialize_multipartform(json_data)
+
+            # httpx determines whether or not to send a "multipart/form-data"
+            # request based on the truthiness of the "files" argument.
+            # This gets around that issue by generating a dict value that
+            # evaluates to true.
+            #
+            # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186
+            if not files:
+                files = cast(HttpxRequestFiles, ForceMultipartDict())
+
+        prepared_url = self._prepare_url(options.url)
+        if "_" in prepared_url.host:
+            # work around https://github.com/encode/httpx/discussions/2880
+            kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
+
+        # TODO: report this error to httpx
+        return self._client.build_request(  # pyright: ignore[reportUnknownMemberType]
+            headers=headers,
+            timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout,
+            method=options.method,
+            url=prepared_url,
+            # the `Query` type that we use is incompatible with qs'
+            # `Params` type as it needs to be typed as `Mapping[str, object]`
+            # so that passing a `TypedDict` doesn't cause an error.
+            # https://github.com/microsoft/pyright/issues/3526#event-6715453066
+            params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
+            json=json_data if is_given(json_data) else None,
+            files=files,
+            **kwargs,
+        )
+
+    def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]:
+        items = self.qs.stringify_items(
+            # TODO: type ignore is required as stringify_items is well typed but we can't be
+            # well typed without heavy validation.
+            data,  # type: ignore
+            array_format="brackets",
+        )
+        serialized: dict[str, object] = {}
+        for key, value in items:
+            existing = serialized.get(key)
+
+            if not existing:
+                serialized[key] = value
+                continue
+
+            # If a value has already been set for this key then that
+            # means we're sending data like `array[]=[1, 2, 3]` and we
+            # need to tell httpx that we want to send multiple values with
+            # the same key which is done by using a list or a tuple.
+            #
+            # Note: 2d arrays should never result in the same key at both
+            # levels so it's safe to assume that if the value is a list,
+            # it was because we changed it to be a list.
+            if is_list(existing):
+                existing.append(value)
+            else:
+                serialized[key] = [existing, value]
+
+        return serialized
+
+    def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]:
+        if not is_given(options.headers):
+            return cast_to
+
+        # make a copy of the headers so we don't mutate user-input
+        headers = dict(options.headers)
+
+        # we internally support defining a temporary header to override the
+        # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response`
+        # see _response.py for implementation details
+        override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN)
+        if is_given(override_cast_to):
+            options.headers = headers
+            return cast(Type[ResponseT], override_cast_to)
+
+        return cast_to
+
+    def _should_stream_response_body(self, request: httpx.Request) -> bool:
+        return request.headers.get(RAW_RESPONSE_HEADER) == "stream"  # type: ignore[no-any-return]
+
+    def _process_response_data(
+        self,
+        *,
+        data: object,
+        cast_to: type[ResponseT],
+        response: httpx.Response,
+    ) -> ResponseT:
+        if data is None:
+            return cast(ResponseT, None)
+
+        if cast_to is object:
+            return cast(ResponseT, data)
+
+        try:
+            if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol):
+                return cast(ResponseT, cast_to.build(response=response, data=data))
+
+            if self._strict_response_validation:
+                return cast(ResponseT, validate_type(type_=cast_to, value=data))
+
+            return cast(ResponseT, construct_type(type_=cast_to, value=data))
+        except pydantic.ValidationError as err:
+            raise APIResponseValidationError(response=response, body=data) from err
+
+    @property
+    def qs(self) -> Querystring:
+        return Querystring()
+
+    @property
+    def custom_auth(self) -> httpx.Auth | None:
+        return None
+
+    @property
+    def auth_headers(self) -> dict[str, str]:
+        return {}
+
+    @property
+    def default_headers(self) -> dict[str, str | Omit]:
+        return {
+            "Accept": "application/json",
+            "Content-Type": "application/json",
+            "User-Agent": self.user_agent,
+            **self.platform_headers(),
+            **self.auth_headers,
+            **self._custom_headers,
+        }
+
+    @property
+    def default_query(self) -> dict[str, object]:
+        return {
+            **self._custom_query,
+        }
+
+    def _validate_headers(
+        self,
+        headers: Headers,  # noqa: ARG002
+        custom_headers: Headers,  # noqa: ARG002
+    ) -> None:
+        """Validate the given default headers and custom headers.
+
+        Does nothing by default.
+        """
+        return
+
+    @property
+    def user_agent(self) -> str:
+        return f"{self.__class__.__name__}/Python {self._version}"
+
+    @property
+    def base_url(self) -> URL:
+        return self._base_url
+
+    @base_url.setter
+    def base_url(self, url: URL | str) -> None:
+        self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url))
+
+    def platform_headers(self) -> Dict[str, str]:
+        # the actual implementation is in a separate `lru_cache` decorated
+        # function because adding `lru_cache` to methods will leak memory
+        # https://github.com/python/cpython/issues/88476
+        return platform_headers(self._version, platform=self._platform)
+
+    def _calculate_nonstreaming_timeout(self, max_tokens: int) -> Timeout:
+        maximum_time = 60 * 60
+        default_time = 60 * 10
+
+        expected_time = maximum_time * max_tokens / 128_000
+        if expected_time > default_time:
+            raise ValueError(
+                "Streaming is strongly recommended for operations that may take longer than 10 minutes. "
+                + "See https://github.com/anthropics/anthropic-sdk-python#long-requests for more details",
+            )
+        return Timeout(
+            default_time,
+            connect=5.0,
+        )
+
+    def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None:
+        """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified.
+
+        About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
+        See also  https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax
+        """
+        if response_headers is None:
+            return None
+
+        # First, try the non-standard `retry-after-ms` header for milliseconds,
+        # which is more precise than integer-seconds `retry-after`
+        try:
+            retry_ms_header = response_headers.get("retry-after-ms", None)
+            return float(retry_ms_header) / 1000
+        except (TypeError, ValueError):
+            pass
+
+        # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats).
+        retry_header = response_headers.get("retry-after")
+        try:
+            # note: the spec indicates that this should only ever be an integer
+            # but if someone sends a float there's no reason for us to not respect it
+            return float(retry_header)
+        except (TypeError, ValueError):
+            pass
+
+        # Last, try parsing `retry-after` as a date.
+        retry_date_tuple = email.utils.parsedate_tz(retry_header)
+        if retry_date_tuple is None:
+            return None
+
+        retry_date = email.utils.mktime_tz(retry_date_tuple)
+        return float(retry_date - time.time())
+
+    def _calculate_retry_timeout(
+        self,
+        remaining_retries: int,
+        options: FinalRequestOptions,
+        response_headers: Optional[httpx.Headers] = None,
+    ) -> float:
+        max_retries = options.get_max_retries(self.max_retries)
+
+        # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says.
+        retry_after = self._parse_retry_after_header(response_headers)
+        if retry_after is not None and 0 < retry_after <= 60:
+            return retry_after
+
+        # Also cap retry count to 1000 to avoid any potential overflows with `pow`
+        nb_retries = min(max_retries - remaining_retries, 1000)
+
+        # Apply exponential backoff, but not more than the max.
+        sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY)
+
+        # Apply some jitter, plus-or-minus half a second.
+        jitter = 1 - 0.25 * random()
+        timeout = sleep_seconds * jitter
+        return timeout if timeout >= 0 else 0
+
+    def _should_retry(self, response: httpx.Response) -> bool:
+        # Note: this is not a standard header
+        should_retry_header = response.headers.get("x-should-retry")
+
+        # If the server explicitly says whether or not to retry, obey.
+        if should_retry_header == "true":
+            log.debug("Retrying as header `x-should-retry` is set to `true`")
+            return True
+        if should_retry_header == "false":
+            log.debug("Not retrying as header `x-should-retry` is set to `false`")
+            return False
+
+        # Retry on request timeouts.
+        if response.status_code == 408:
+            log.debug("Retrying due to status code %i", response.status_code)
+            return True
+
+        # Retry on lock timeouts.
+        if response.status_code == 409:
+            log.debug("Retrying due to status code %i", response.status_code)
+            return True
+
+        # Retry on rate limits.
+        if response.status_code == 429:
+            log.debug("Retrying due to status code %i", response.status_code)
+            return True
+
+        # Retry internal errors.
+        if response.status_code >= 500:
+            log.debug("Retrying due to status code %i", response.status_code)
+            return True
+
+        log.debug("Not retrying")
+        return False
+
+    def _idempotency_key(self) -> str:
+        return f"stainless-python-retry-{uuid.uuid4()}"
+
+
+class _DefaultHttpxClient(httpx.Client):
+    def __init__(self, **kwargs: Any) -> None:
+        kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
+        kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
+        kwargs.setdefault("follow_redirects", True)
+
+        if "transport" not in kwargs:
+            socket_options = [
+                (socket.SOL_SOCKET, socket.SO_KEEPALIVE, True),
+                (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 60),
+                (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5),
+            ]
+            TCP_KEEPIDLE = getattr(socket, "TCP_KEEPIDLE", None)
+            if TCP_KEEPIDLE is not None:
+                socket_options.append((socket.IPPROTO_TCP, TCP_KEEPIDLE, 60))
+
+            kwargs["transport"] = httpx.HTTPTransport(
+                # note: limits is always set above
+                limits=kwargs["limits"],
+                socket_options=socket_options,
+            )
+
+        super().__init__(**kwargs)
+
+
+if TYPE_CHECKING:
+    DefaultHttpxClient = httpx.Client
+    """An alias to `httpx.Client` that provides the same defaults that this SDK
+    uses internally.
+
+    This is useful because overriding the `http_client` with your own instance of
+    `httpx.Client` will result in httpx's defaults being used, not ours.
+    """
+else:
+    DefaultHttpxClient = _DefaultHttpxClient
+
+
+class SyncHttpxClientWrapper(DefaultHttpxClient):
+    def __del__(self) -> None:
+        if self.is_closed:
+            return
+
+        try:
+            self.close()
+        except Exception:
+            pass
+
+
+class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
+    _client: httpx.Client
+    _default_stream_cls: type[Stream[Any]] | None = None
+
+    def __init__(
+        self,
+        *,
+        version: str,
+        base_url: str | URL,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
+        transport: Transport | None = None,
+        proxies: ProxiesTypes | None = None,
+        limits: Limits | None = None,
+        http_client: httpx.Client | None = None,
+        custom_headers: Mapping[str, str] | None = None,
+        custom_query: Mapping[str, object] | None = None,
+        _strict_response_validation: bool,
+    ) -> None:
+        kwargs: dict[str, Any] = {}
+        if limits is not None:
+            warnings.warn(
+                "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead",
+                category=DeprecationWarning,
+                stacklevel=3,
+            )
+            if http_client is not None:
+                raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`")
+        else:
+            limits = DEFAULT_CONNECTION_LIMITS
+
+        if transport is not None:
+            kwargs["transport"] = transport
+            warnings.warn(
+                "The `transport` argument is deprecated. The `http_client` argument should be passed instead",
+                category=DeprecationWarning,
+                stacklevel=3,
+            )
+            if http_client is not None:
+                raise ValueError("The `http_client` argument is mutually exclusive with `transport`")
+
+        if proxies is not None:
+            kwargs["proxies"] = proxies
+            warnings.warn(
+                "The `proxies` argument is deprecated. The `http_client` argument should be passed instead",
+                category=DeprecationWarning,
+                stacklevel=3,
+            )
+            if http_client is not None:
+                raise ValueError("The `http_client` argument is mutually exclusive with `proxies`")
+
+        if not is_given(timeout):
+            # if the user passed in a custom http client with a non-default
+            # timeout set then we use that timeout.
+            #
+            # note: there is an edge case here where the user passes in a client
+            # where they've explicitly set the timeout to match the default timeout
+            # as this check is structural, meaning that we'll think they didn't
+            # pass in a timeout and will ignore it
+            if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT:
+                timeout = http_client.timeout
+            else:
+                timeout = DEFAULT_TIMEOUT
+
+        if http_client is not None and not isinstance(http_client, httpx.Client):  # pyright: ignore[reportUnnecessaryIsInstance]
+            raise TypeError(
+                f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}"
+            )
+
+        super().__init__(
+            version=version,
+            limits=limits,
+            # cast to a valid type because mypy doesn't understand our type narrowing
+            timeout=cast(Timeout, timeout),
+            proxies=proxies,
+            base_url=base_url,
+            transport=transport,
+            max_retries=max_retries,
+            custom_query=custom_query,
+            custom_headers=custom_headers,
+            _strict_response_validation=_strict_response_validation,
+        )
+        self._client = http_client or SyncHttpxClientWrapper(
+            base_url=base_url,
+            # cast to a valid type because mypy doesn't understand our type narrowing
+            timeout=cast(Timeout, timeout),
+            limits=limits,
+            follow_redirects=True,
+            **kwargs,  # type: ignore
+        )
+
+    def is_closed(self) -> bool:
+        return self._client.is_closed
+
+    def close(self) -> None:
+        """Close the underlying HTTPX client.
+
+        The client will *not* be usable after this.
+        """
+        # If an error is thrown while constructing a client, self._client
+        # may not be present
+        if hasattr(self, "_client"):
+            self._client.close()
+
+    def __enter__(self: _T) -> _T:
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.close()
+
+    def _prepare_options(
+        self,
+        options: FinalRequestOptions,  # noqa: ARG002
+    ) -> FinalRequestOptions:
+        """Hook for mutating the given options"""
+        return options
+
+    def _prepare_request(
+        self,
+        request: httpx.Request,  # noqa: ARG002
+    ) -> None:
+        """This method is used as a callback for mutating the `Request` object
+        after it has been constructed.
+        This is useful for cases where you want to add certain headers based off of
+        the request properties, e.g. `url`, `method` etc.
+        """
+        return None
+
+    @overload
+    def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        remaining_retries: Optional[int] = None,
+        *,
+        stream: Literal[True],
+        stream_cls: Type[_StreamT],
+    ) -> _StreamT: ...
+
+    @overload
+    def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        remaining_retries: Optional[int] = None,
+        *,
+        stream: Literal[False] = False,
+    ) -> ResponseT: ...
+
+    @overload
+    def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        remaining_retries: Optional[int] = None,
+        *,
+        stream: bool = False,
+        stream_cls: Type[_StreamT] | None = None,
+    ) -> ResponseT | _StreamT: ...
+
+    def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        remaining_retries: Optional[int] = None,
+        *,
+        stream: bool = False,
+        stream_cls: type[_StreamT] | None = None,
+    ) -> ResponseT | _StreamT:
+        if remaining_retries is not None:
+            retries_taken = options.get_max_retries(self.max_retries) - remaining_retries
+        else:
+            retries_taken = 0
+
+        return self._request(
+            cast_to=cast_to,
+            options=options,
+            stream=stream,
+            stream_cls=stream_cls,
+            retries_taken=retries_taken,
+        )
+
+    def _request(
+        self,
+        *,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        retries_taken: int,
+        stream: bool,
+        stream_cls: type[_StreamT] | None,
+    ) -> ResponseT | _StreamT:
+        # create a copy of the options we were given so that if the
+        # options are mutated later & we then retry, the retries are
+        # given the original options
+        input_options = model_copy(options)
+
+        cast_to = self._maybe_override_cast_to(cast_to, options)
+        options = self._prepare_options(options)
+
+        remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
+        request = self._build_request(options, retries_taken=retries_taken)
+        self._prepare_request(request)
+
+        kwargs: HttpxSendArgs = {}
+        if self.custom_auth is not None:
+            kwargs["auth"] = self.custom_auth
+
+        log.debug("Sending HTTP Request: %s %s", request.method, request.url)
+
+        try:
+            response = self._client.send(
+                request,
+                stream=stream or self._should_stream_response_body(request=request),
+                **kwargs,
+            )
+        except httpx.TimeoutException as err:
+            log.debug("Encountered httpx.TimeoutException", exc_info=True)
+
+            if remaining_retries > 0:
+                return self._retry_request(
+                    input_options,
+                    cast_to,
+                    retries_taken=retries_taken,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    response_headers=None,
+                )
+
+            log.debug("Raising timeout error")
+            raise APITimeoutError(request=request) from err
+        except Exception as err:
+            log.debug("Encountered Exception", exc_info=True)
+
+            if remaining_retries > 0:
+                return self._retry_request(
+                    input_options,
+                    cast_to,
+                    retries_taken=retries_taken,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    response_headers=None,
+                )
+
+            log.debug("Raising connection error")
+            raise APIConnectionError(request=request) from err
+
+        log.debug(
+            'HTTP Response: %s %s "%i %s" %s',
+            request.method,
+            request.url,
+            response.status_code,
+            response.reason_phrase,
+            response.headers,
+        )
+        log.debug("request_id: %s", response.headers.get("request-id"))
+
+        try:
+            response.raise_for_status()
+        except httpx.HTTPStatusError as err:  # thrown on 4xx and 5xx status code
+            log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
+
+            if remaining_retries > 0 and self._should_retry(err.response):
+                err.response.close()
+                return self._retry_request(
+                    input_options,
+                    cast_to,
+                    retries_taken=retries_taken,
+                    response_headers=err.response.headers,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                )
+
+            # If the response is streamed then we need to explicitly read the response
+            # to completion before attempting to access the response text.
+            if not err.response.is_closed:
+                err.response.read()
+
+            log.debug("Re-raising status error")
+            raise self._make_status_error_from_response(err.response) from None
+
+        return self._process_response(
+            cast_to=cast_to,
+            options=options,
+            response=response,
+            stream=stream,
+            stream_cls=stream_cls,
+            retries_taken=retries_taken,
+        )
+
+    def _retry_request(
+        self,
+        options: FinalRequestOptions,
+        cast_to: Type[ResponseT],
+        *,
+        retries_taken: int,
+        response_headers: httpx.Headers | None,
+        stream: bool,
+        stream_cls: type[_StreamT] | None,
+    ) -> ResponseT | _StreamT:
+        remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
+        if remaining_retries == 1:
+            log.debug("1 retry left")
+        else:
+            log.debug("%i retries left", remaining_retries)
+
+        timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers)
+        log.info("Retrying request to %s in %f seconds", options.url, timeout)
+
+        # In a synchronous context we are blocking the entire thread. Up to the library user to run the client in a
+        # different thread if necessary.
+        time.sleep(timeout)
+
+        return self._request(
+            options=options,
+            cast_to=cast_to,
+            retries_taken=retries_taken + 1,
+            stream=stream,
+            stream_cls=stream_cls,
+        )
+
+    def _process_response(
+        self,
+        *,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        response: httpx.Response,
+        stream: bool,
+        stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
+        retries_taken: int = 0,
+    ) -> ResponseT:
+        if response.request.headers.get(RAW_RESPONSE_HEADER) == "true":
+            return cast(
+                ResponseT,
+                LegacyAPIResponse(
+                    raw=response,
+                    client=self,
+                    cast_to=cast_to,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    options=options,
+                    retries_taken=retries_taken,
+                ),
+            )
+
+        origin = get_origin(cast_to) or cast_to
+
+        if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
+            if not issubclass(origin, APIResponse):
+                raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
+
+            response_cls = cast("type[BaseAPIResponse[Any]]", cast_to)
+            return cast(
+                ResponseT,
+                response_cls(
+                    raw=response,
+                    client=self,
+                    cast_to=extract_response_type(response_cls),
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    options=options,
+                    retries_taken=retries_taken,
+                ),
+            )
+
+        if cast_to == httpx.Response:
+            return cast(ResponseT, response)
+
+        api_response = APIResponse(
+            raw=response,
+            client=self,
+            cast_to=cast("type[ResponseT]", cast_to),  # pyright: ignore[reportUnnecessaryCast]
+            stream=stream,
+            stream_cls=stream_cls,
+            options=options,
+            retries_taken=retries_taken,
+        )
+        if bool(response.request.headers.get(RAW_RESPONSE_HEADER)):
+            return cast(ResponseT, api_response)
+
+        return api_response.parse()
+
+    def _request_api_list(
+        self,
+        model: Type[object],
+        page: Type[SyncPageT],
+        options: FinalRequestOptions,
+    ) -> SyncPageT:
+        def _parser(resp: SyncPageT) -> SyncPageT:
+            resp._set_private_attributes(
+                client=self,
+                model=model,
+                options=options,
+            )
+            return resp
+
+        options.post_parser = _parser
+
+        return self.request(page, options, stream=False)
+
+    @overload
+    def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: Literal[False] = False,
+    ) -> ResponseT: ...
+
+    @overload
+    def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: Literal[True],
+        stream_cls: type[_StreamT],
+    ) -> _StreamT: ...
+
+    @overload
+    def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: bool,
+        stream_cls: type[_StreamT] | None = None,
+    ) -> ResponseT | _StreamT: ...
+
+    def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: bool = False,
+        stream_cls: type[_StreamT] | None = None,
+    ) -> ResponseT | _StreamT:
+        opts = FinalRequestOptions.construct(method="get", url=path, **options)
+        # cast is required because mypy complains about returning Any even though
+        # it understands the type variables
+        return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
+
+    @overload
+    def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+        files: RequestFiles | None = None,
+        stream: Literal[False] = False,
+    ) -> ResponseT: ...
+
+    @overload
+    def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+        files: RequestFiles | None = None,
+        stream: Literal[True],
+        stream_cls: type[_StreamT],
+    ) -> _StreamT: ...
+
+    @overload
+    def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+        files: RequestFiles | None = None,
+        stream: bool,
+        stream_cls: type[_StreamT] | None = None,
+    ) -> ResponseT | _StreamT: ...
+
+    def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+        files: RequestFiles | None = None,
+        stream: bool = False,
+        stream_cls: type[_StreamT] | None = None,
+    ) -> ResponseT | _StreamT:
+        opts = FinalRequestOptions.construct(
+            method="post", url=path, json_data=body, files=to_httpx_files(files), **options
+        )
+        return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
+
+    def patch(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+    ) -> ResponseT:
+        opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options)
+        return self.request(cast_to, opts)
+
+    def put(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        files: RequestFiles | None = None,
+        options: RequestOptions = {},
+    ) -> ResponseT:
+        opts = FinalRequestOptions.construct(
+            method="put", url=path, json_data=body, files=to_httpx_files(files), **options
+        )
+        return self.request(cast_to, opts)
+
+    def delete(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+    ) -> ResponseT:
+        opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+        return self.request(cast_to, opts)
+
+    def get_api_list(
+        self,
+        path: str,
+        *,
+        model: Type[object],
+        page: Type[SyncPageT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+        method: str = "get",
+    ) -> SyncPageT:
+        opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options)
+        return self._request_api_list(model, page, opts)
+
+
+class _DefaultAsyncHttpxClient(httpx.AsyncClient):
+    def __init__(self, **kwargs: Any) -> None:
+        kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
+        kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
+        kwargs.setdefault("follow_redirects", True)
+
+        if "transport" not in kwargs:
+            socket_options = [
+                (socket.SOL_SOCKET, socket.SO_KEEPALIVE, True),
+                (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 60),
+                (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5),
+            ]
+            TCP_KEEPIDLE = getattr(socket, "TCP_KEEPIDLE", None)
+            if TCP_KEEPIDLE is not None:
+                socket_options.append((socket.IPPROTO_TCP, TCP_KEEPIDLE, 60))
+
+            kwargs["transport"] = httpx.AsyncHTTPTransport(
+                # note: limits is always set above
+                limits=kwargs["limits"],
+                socket_options=socket_options,
+            )
+
+        super().__init__(**kwargs)
+
+
+if TYPE_CHECKING:
+    DefaultAsyncHttpxClient = httpx.AsyncClient
+    """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
+    uses internally.
+
+    This is useful because overriding the `http_client` with your own instance of
+    `httpx.AsyncClient` will result in httpx's defaults being used, not ours.
+    """
+else:
+    DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
+
+
+class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
+    def __del__(self) -> None:
+        if self.is_closed:
+            return
+
+        try:
+            # TODO(someday): support non asyncio runtimes here
+            asyncio.get_running_loop().create_task(self.aclose())
+        except Exception:
+            pass
+
+
+class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
+    _client: httpx.AsyncClient
+    _default_stream_cls: type[AsyncStream[Any]] | None = None
+
+    def __init__(
+        self,
+        *,
+        version: str,
+        base_url: str | URL,
+        _strict_response_validation: bool,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
+        transport: AsyncTransport | None = None,
+        proxies: ProxiesTypes | None = None,
+        limits: Limits | None = None,
+        http_client: httpx.AsyncClient | None = None,
+        custom_headers: Mapping[str, str] | None = None,
+        custom_query: Mapping[str, object] | None = None,
+    ) -> None:
+        kwargs: dict[str, Any] = {}
+        if limits is not None:
+            warnings.warn(
+                "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead",
+                category=DeprecationWarning,
+                stacklevel=3,
+            )
+            if http_client is not None:
+                raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`")
+        else:
+            limits = DEFAULT_CONNECTION_LIMITS
+
+        if transport is not None:
+            kwargs["transport"] = transport
+
+            warnings.warn(
+                "The `transport` argument is deprecated. The `http_client` argument should be passed instead",
+                category=DeprecationWarning,
+                stacklevel=3,
+            )
+            if http_client is not None:
+                raise ValueError("The `http_client` argument is mutually exclusive with `transport`")
+
+        if proxies is not None:
+            kwargs["proxies"] = proxies
+            warnings.warn(
+                "The `proxies` argument is deprecated. The `http_client` argument should be passed instead",
+                category=DeprecationWarning,
+                stacklevel=3,
+            )
+            if http_client is not None:
+                raise ValueError("The `http_client` argument is mutually exclusive with `proxies`")
+
+        if not is_given(timeout):
+            # if the user passed in a custom http client with a non-default
+            # timeout set then we use that timeout.
+            #
+            # note: there is an edge case here where the user passes in a client
+            # where they've explicitly set the timeout to match the default timeout
+            # as this check is structural, meaning that we'll think they didn't
+            # pass in a timeout and will ignore it
+            if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT:
+                timeout = http_client.timeout
+            else:
+                timeout = DEFAULT_TIMEOUT
+
+        if http_client is not None and not isinstance(http_client, httpx.AsyncClient):  # pyright: ignore[reportUnnecessaryIsInstance]
+            raise TypeError(
+                f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}"
+            )
+
+        super().__init__(
+            version=version,
+            base_url=base_url,
+            limits=limits,
+            # cast to a valid type because mypy doesn't understand our type narrowing
+            timeout=cast(Timeout, timeout),
+            proxies=proxies,
+            transport=transport,
+            max_retries=max_retries,
+            custom_query=custom_query,
+            custom_headers=custom_headers,
+            _strict_response_validation=_strict_response_validation,
+        )
+        self._client = http_client or AsyncHttpxClientWrapper(
+            base_url=base_url,
+            # cast to a valid type because mypy doesn't understand our type narrowing
+            timeout=cast(Timeout, timeout),
+            limits=limits,
+            follow_redirects=True,
+            **kwargs,  # type: ignore
+        )
+
+    def is_closed(self) -> bool:
+        return self._client.is_closed
+
+    async def close(self) -> None:
+        """Close the underlying HTTPX client.
+
+        The client will *not* be usable after this.
+        """
+        await self._client.aclose()
+
+    async def __aenter__(self: _T) -> _T:
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        await self.close()
+
+    async def _prepare_options(
+        self,
+        options: FinalRequestOptions,  # noqa: ARG002
+    ) -> FinalRequestOptions:
+        """Hook for mutating the given options"""
+        return options
+
+    async def _prepare_request(
+        self,
+        request: httpx.Request,  # noqa: ARG002
+    ) -> None:
+        """This method is used as a callback for mutating the `Request` object
+        after it has been constructed.
+        This is useful for cases where you want to add certain headers based off of
+        the request properties, e.g. `url`, `method` etc.
+        """
+        return None
+
+    @overload
+    async def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        *,
+        stream: Literal[False] = False,
+        remaining_retries: Optional[int] = None,
+    ) -> ResponseT: ...
+
+    @overload
+    async def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        *,
+        stream: Literal[True],
+        stream_cls: type[_AsyncStreamT],
+        remaining_retries: Optional[int] = None,
+    ) -> _AsyncStreamT: ...
+
+    @overload
+    async def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        *,
+        stream: bool,
+        stream_cls: type[_AsyncStreamT] | None = None,
+        remaining_retries: Optional[int] = None,
+    ) -> ResponseT | _AsyncStreamT: ...
+
+    async def request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        *,
+        stream: bool = False,
+        stream_cls: type[_AsyncStreamT] | None = None,
+        remaining_retries: Optional[int] = None,
+    ) -> ResponseT | _AsyncStreamT:
+        if remaining_retries is not None:
+            retries_taken = options.get_max_retries(self.max_retries) - remaining_retries
+        else:
+            retries_taken = 0
+
+        return await self._request(
+            cast_to=cast_to,
+            options=options,
+            stream=stream,
+            stream_cls=stream_cls,
+            retries_taken=retries_taken,
+        )
+
+    async def _request(
+        self,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        *,
+        stream: bool,
+        stream_cls: type[_AsyncStreamT] | None,
+        retries_taken: int,
+    ) -> ResponseT | _AsyncStreamT:
+        if self._platform is None:
+            # `get_platform` can make blocking IO calls so we
+            # execute it earlier while we are in an async context
+            self._platform = await asyncify(get_platform)()
+
+        # create a copy of the options we were given so that if the
+        # options are mutated later & we then retry, the retries are
+        # given the original options
+        input_options = model_copy(options)
+
+        cast_to = self._maybe_override_cast_to(cast_to, options)
+        options = await self._prepare_options(options)
+
+        remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
+        request = self._build_request(options, retries_taken=retries_taken)
+        await self._prepare_request(request)
+
+        kwargs: HttpxSendArgs = {}
+        if self.custom_auth is not None:
+            kwargs["auth"] = self.custom_auth
+
+        try:
+            response = await self._client.send(
+                request,
+                stream=stream or self._should_stream_response_body(request=request),
+                **kwargs,
+            )
+        except httpx.TimeoutException as err:
+            log.debug("Encountered httpx.TimeoutException", exc_info=True)
+
+            if remaining_retries > 0:
+                return await self._retry_request(
+                    input_options,
+                    cast_to,
+                    retries_taken=retries_taken,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    response_headers=None,
+                )
+
+            log.debug("Raising timeout error")
+            raise APITimeoutError(request=request) from err
+        except Exception as err:
+            log.debug("Encountered Exception", exc_info=True)
+
+            if remaining_retries > 0:
+                return await self._retry_request(
+                    input_options,
+                    cast_to,
+                    retries_taken=retries_taken,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    response_headers=None,
+                )
+
+            log.debug("Raising connection error")
+            raise APIConnectionError(request=request) from err
+
+        log.debug(
+            'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
+        )
+
+        try:
+            response.raise_for_status()
+        except httpx.HTTPStatusError as err:  # thrown on 4xx and 5xx status code
+            log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
+
+            if remaining_retries > 0 and self._should_retry(err.response):
+                await err.response.aclose()
+                return await self._retry_request(
+                    input_options,
+                    cast_to,
+                    retries_taken=retries_taken,
+                    response_headers=err.response.headers,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                )
+
+            # If the response is streamed then we need to explicitly read the response
+            # to completion before attempting to access the response text.
+            if not err.response.is_closed:
+                await err.response.aread()
+
+            log.debug("Re-raising status error")
+            raise self._make_status_error_from_response(err.response) from None
+
+        return await self._process_response(
+            cast_to=cast_to,
+            options=options,
+            response=response,
+            stream=stream,
+            stream_cls=stream_cls,
+            retries_taken=retries_taken,
+        )
+
+    async def _retry_request(
+        self,
+        options: FinalRequestOptions,
+        cast_to: Type[ResponseT],
+        *,
+        retries_taken: int,
+        response_headers: httpx.Headers | None,
+        stream: bool,
+        stream_cls: type[_AsyncStreamT] | None,
+    ) -> ResponseT | _AsyncStreamT:
+        remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
+        if remaining_retries == 1:
+            log.debug("1 retry left")
+        else:
+            log.debug("%i retries left", remaining_retries)
+
+        timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers)
+        log.info("Retrying request to %s in %f seconds", options.url, timeout)
+
+        await anyio.sleep(timeout)
+
+        return await self._request(
+            options=options,
+            cast_to=cast_to,
+            retries_taken=retries_taken + 1,
+            stream=stream,
+            stream_cls=stream_cls,
+        )
+
+    async def _process_response(
+        self,
+        *,
+        cast_to: Type[ResponseT],
+        options: FinalRequestOptions,
+        response: httpx.Response,
+        stream: bool,
+        stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
+        retries_taken: int = 0,
+    ) -> ResponseT:
+        if response.request.headers.get(RAW_RESPONSE_HEADER) == "true":
+            return cast(
+                ResponseT,
+                LegacyAPIResponse(
+                    raw=response,
+                    client=self,
+                    cast_to=cast_to,
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    options=options,
+                    retries_taken=retries_taken,
+                ),
+            )
+
+        origin = get_origin(cast_to) or cast_to
+
+        if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
+            if not issubclass(origin, AsyncAPIResponse):
+                raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
+
+            response_cls = cast("type[BaseAPIResponse[Any]]", cast_to)
+            return cast(
+                "ResponseT",
+                response_cls(
+                    raw=response,
+                    client=self,
+                    cast_to=extract_response_type(response_cls),
+                    stream=stream,
+                    stream_cls=stream_cls,
+                    options=options,
+                    retries_taken=retries_taken,
+                ),
+            )
+
+        if cast_to == httpx.Response:
+            return cast(ResponseT, response)
+
+        api_response = AsyncAPIResponse(
+            raw=response,
+            client=self,
+            cast_to=cast("type[ResponseT]", cast_to),  # pyright: ignore[reportUnnecessaryCast]
+            stream=stream,
+            stream_cls=stream_cls,
+            options=options,
+            retries_taken=retries_taken,
+        )
+        if bool(response.request.headers.get(RAW_RESPONSE_HEADER)):
+            return cast(ResponseT, api_response)
+
+        return await api_response.parse()
+
+    def _request_api_list(
+        self,
+        model: Type[_T],
+        page: Type[AsyncPageT],
+        options: FinalRequestOptions,
+    ) -> AsyncPaginator[_T, AsyncPageT]:
+        return AsyncPaginator(client=self, options=options, page_cls=page, model=model)
+
+    @overload
+    async def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: Literal[False] = False,
+    ) -> ResponseT: ...
+
+    @overload
+    async def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: Literal[True],
+        stream_cls: type[_AsyncStreamT],
+    ) -> _AsyncStreamT: ...
+
+    @overload
+    async def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: bool,
+        stream_cls: type[_AsyncStreamT] | None = None,
+    ) -> ResponseT | _AsyncStreamT: ...
+
+    async def get(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        options: RequestOptions = {},
+        stream: bool = False,
+        stream_cls: type[_AsyncStreamT] | None = None,
+    ) -> ResponseT | _AsyncStreamT:
+        opts = FinalRequestOptions.construct(method="get", url=path, **options)
+        return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
+
+    @overload
+    async def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        files: RequestFiles | None = None,
+        options: RequestOptions = {},
+        stream: Literal[False] = False,
+    ) -> ResponseT: ...
+
+    @overload
+    async def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        files: RequestFiles | None = None,
+        options: RequestOptions = {},
+        stream: Literal[True],
+        stream_cls: type[_AsyncStreamT],
+    ) -> _AsyncStreamT: ...
+
+    @overload
+    async def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        files: RequestFiles | None = None,
+        options: RequestOptions = {},
+        stream: bool,
+        stream_cls: type[_AsyncStreamT] | None = None,
+    ) -> ResponseT | _AsyncStreamT: ...
+
+    async def post(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        files: RequestFiles | None = None,
+        options: RequestOptions = {},
+        stream: bool = False,
+        stream_cls: type[_AsyncStreamT] | None = None,
+    ) -> ResponseT | _AsyncStreamT:
+        opts = FinalRequestOptions.construct(
+            method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+        )
+        return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
+
+    async def patch(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+    ) -> ResponseT:
+        opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options)
+        return await self.request(cast_to, opts)
+
+    async def put(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        files: RequestFiles | None = None,
+        options: RequestOptions = {},
+    ) -> ResponseT:
+        opts = FinalRequestOptions.construct(
+            method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+        )
+        return await self.request(cast_to, opts)
+
+    async def delete(
+        self,
+        path: str,
+        *,
+        cast_to: Type[ResponseT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+    ) -> ResponseT:
+        opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+        return await self.request(cast_to, opts)
+
+    def get_api_list(
+        self,
+        path: str,
+        *,
+        model: Type[_T],
+        page: Type[AsyncPageT],
+        body: Body | None = None,
+        options: RequestOptions = {},
+        method: str = "get",
+    ) -> AsyncPaginator[_T, AsyncPageT]:
+        opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options)
+        return self._request_api_list(model, page, opts)
+
+
+def make_request_options(
+    *,
+    query: Query | None = None,
+    extra_headers: Headers | None = None,
+    extra_query: Query | None = None,
+    extra_body: Body | None = None,
+    idempotency_key: str | None = None,
+    timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    post_parser: PostParser | NotGiven = NOT_GIVEN,
+) -> RequestOptions:
+    """Create a dict of type RequestOptions without keys of NotGiven values."""
+    options: RequestOptions = {}
+    if extra_headers is not None:
+        options["headers"] = extra_headers
+
+    if extra_body is not None:
+        options["extra_json"] = cast(AnyMapping, extra_body)
+
+    if query is not None:
+        options["params"] = query
+
+    if extra_query is not None:
+        options["params"] = {**options.get("params", {}), **extra_query}
+
+    if not isinstance(timeout, NotGiven):
+        options["timeout"] = timeout
+
+    if idempotency_key is not None:
+        options["idempotency_key"] = idempotency_key
+
+    if is_given(post_parser):
+        # internal
+        options["post_parser"] = post_parser  # type: ignore
+
+    return options
+
+
+class ForceMultipartDict(Dict[str, None]):
+    def __bool__(self) -> bool:
+        return True
+
+
+class OtherPlatform:
+    def __init__(self, name: str) -> None:
+        self.name = name
+
+    @override
+    def __str__(self) -> str:
+        return f"Other:{self.name}"
+
+
+Platform = Union[
+    OtherPlatform,
+    Literal[
+        "MacOS",
+        "Linux",
+        "Windows",
+        "FreeBSD",
+        "OpenBSD",
+        "iOS",
+        "Android",
+        "Unknown",
+    ],
+]
+
+
+def get_platform() -> Platform:
+    try:
+        system = platform.system().lower()
+        platform_name = platform.platform().lower()
+    except Exception:
+        return "Unknown"
+
+    if "iphone" in platform_name or "ipad" in platform_name:
+        # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7
+        # system is Darwin and platform_name is a string like:
+        # - Darwin-21.6.0-iPhone12,1-64bit
+        # - Darwin-21.6.0-iPad7,11-64bit
+        return "iOS"
+
+    if system == "darwin":
+        return "MacOS"
+
+    if system == "windows":
+        return "Windows"
+
+    if "android" in platform_name:
+        # Tested using Pydroid 3
+        # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc'
+        return "Android"
+
+    if system == "linux":
+        # https://distro.readthedocs.io/en/latest/#distro.id
+        distro_id = distro.id()
+        if distro_id == "freebsd":
+            return "FreeBSD"
+
+        if distro_id == "openbsd":
+            return "OpenBSD"
+
+        return "Linux"
+
+    if platform_name:
+        return OtherPlatform(platform_name)
+
+    return "Unknown"
+
+
+@lru_cache(maxsize=None)
+def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]:
+    return {
+        "X-Stainless-Lang": "python",
+        "X-Stainless-Package-Version": version,
+        "X-Stainless-OS": str(platform or get_platform()),
+        "X-Stainless-Arch": str(get_architecture()),
+        "X-Stainless-Runtime": get_python_runtime(),
+        "X-Stainless-Runtime-Version": get_python_version(),
+    }
+
+
+class OtherArch:
+    def __init__(self, name: str) -> None:
+        self.name = name
+
+    @override
+    def __str__(self) -> str:
+        return f"other:{self.name}"
+
+
+Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]]
+
+
+def get_python_runtime() -> str:
+    try:
+        return platform.python_implementation()
+    except Exception:
+        return "unknown"
+
+
+def get_python_version() -> str:
+    try:
+        return platform.python_version()
+    except Exception:
+        return "unknown"
+
+
+def get_architecture() -> Arch:
+    try:
+        machine = platform.machine().lower()
+    except Exception:
+        return "unknown"
+
+    if machine in ("arm64", "aarch64"):
+        return "arm64"
+
+    # TODO: untested
+    if machine == "arm":
+        return "arm"
+
+    if machine == "x86_64":
+        return "x64"
+
+    # TODO: untested
+    if sys.maxsize <= 2**32:
+        return "x32"
+
+    if machine:
+        return OtherArch(machine)
+
+    return "unknown"
+
+
+def _merge_mappings(
+    obj1: Mapping[_T_co, Union[_T, Omit]],
+    obj2: Mapping[_T_co, Union[_T, Omit]],
+) -> Dict[_T_co, _T]:
+    """Merge two mappings of the same type, removing any values that are instances of `Omit`.
+
+    In cases with duplicate keys the second mapping takes precedence.
+    """
+    merged = {**obj1, **obj2}
+    return {key: value for key, value in merged.items() if not isinstance(value, Omit)}
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_client.py b/.venv/lib/python3.12/site-packages/anthropic/_client.py
new file mode 100644
index 00000000..842e26b5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_client.py
@@ -0,0 +1,531 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, Union, Mapping
+from typing_extensions import Self, override
+
+import httpx
+
+from . import _constants, _exceptions
+from ._qs import Querystring
+from ._types import (
+    NOT_GIVEN,
+    Omit,
+    Headers,
+    Timeout,
+    NotGiven,
+    Transport,
+    ProxiesTypes,
+    RequestOptions,
+)
+from ._utils import (
+    is_given,
+    get_async_library,
+)
+from ._version import __version__
+from .resources import models, completions
+from ._streaming import Stream as Stream, AsyncStream as AsyncStream
+from ._exceptions import APIStatusError
+from ._base_client import (
+    DEFAULT_MAX_RETRIES,
+    SyncAPIClient,
+    AsyncAPIClient,
+)
+from .resources.beta import beta
+from .resources.messages import messages
+
+__all__ = [
+    "Timeout",
+    "Transport",
+    "ProxiesTypes",
+    "RequestOptions",
+    "Anthropic",
+    "AsyncAnthropic",
+    "Client",
+    "AsyncClient",
+]
+
+
+class Anthropic(SyncAPIClient):
+    completions: completions.Completions
+    messages: messages.Messages
+    models: models.Models
+    beta: beta.Beta
+    with_raw_response: AnthropicWithRawResponse
+    with_streaming_response: AnthropicWithStreamedResponse
+
+    # client options
+    api_key: str | None
+    auth_token: str | None
+
+    # constants
+    HUMAN_PROMPT = _constants.HUMAN_PROMPT
+    AI_PROMPT = _constants.AI_PROMPT
+
+    def __init__(
+        self,
+        *,
+        api_key: str | None = None,
+        auth_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        # Configure a custom httpx client.
+        # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`.
+        # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
+        http_client: httpx.Client | None = None,
+        # Enable or disable schema validation for data returned by the API.
+        # When enabled an error APIResponseValidationError is raised
+        # if the API responds with invalid data for the expected schema.
+        #
+        # This parameter may be removed or changed in the future.
+        # If you rely on this feature, please open a GitHub issue
+        # outlining your use-case to help us decide if it should be
+        # part of our public interface in the future.
+        _strict_response_validation: bool = False,
+    ) -> None:
+        """Construct a new synchronous Anthropic client instance.
+
+        This automatically infers the following arguments from their corresponding environment variables if they are not provided:
+        - `api_key` from `ANTHROPIC_API_KEY`
+        - `auth_token` from `ANTHROPIC_AUTH_TOKEN`
+        """
+        if api_key is None:
+            api_key = os.environ.get("ANTHROPIC_API_KEY")
+        self.api_key = api_key
+
+        if auth_token is None:
+            auth_token = os.environ.get("ANTHROPIC_AUTH_TOKEN")
+        self.auth_token = auth_token
+
+        if base_url is None:
+            base_url = os.environ.get("ANTHROPIC_BASE_URL")
+        if base_url is None:
+            base_url = f"https://api.anthropic.com"
+
+        super().__init__(
+            version=__version__,
+            base_url=base_url,
+            max_retries=max_retries,
+            timeout=timeout,
+            http_client=http_client,
+            custom_headers=default_headers,
+            custom_query=default_query,
+            _strict_response_validation=_strict_response_validation,
+        )
+
+        self._default_stream_cls = Stream
+
+        self.completions = completions.Completions(self)
+        self.messages = messages.Messages(self)
+        self.models = models.Models(self)
+        self.beta = beta.Beta(self)
+        self.with_raw_response = AnthropicWithRawResponse(self)
+        self.with_streaming_response = AnthropicWithStreamedResponse(self)
+
+    @property
+    @override
+    def qs(self) -> Querystring:
+        return Querystring(array_format="comma")
+
+    @property
+    @override
+    def auth_headers(self) -> dict[str, str]:
+        if self._api_key_auth:
+            return self._api_key_auth
+        if self._bearer_auth:
+            return self._bearer_auth
+        return {}
+
+    @property
+    def _api_key_auth(self) -> dict[str, str]:
+        api_key = self.api_key
+        if api_key is None:
+            return {}
+        return {"X-Api-Key": api_key}
+
+    @property
+    def _bearer_auth(self) -> dict[str, str]:
+        auth_token = self.auth_token
+        if auth_token is None:
+            return {}
+        return {"Authorization": f"Bearer {auth_token}"}
+
+    @property
+    @override
+    def default_headers(self) -> dict[str, str | Omit]:
+        return {
+            **super().default_headers,
+            "X-Stainless-Async": "false",
+            "anthropic-version": "2023-06-01",
+            **self._custom_headers,
+        }
+
+    @override
+    def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None:
+        if self.api_key and headers.get("X-Api-Key"):
+            return
+        if isinstance(custom_headers.get("X-Api-Key"), Omit):
+            return
+
+        if self.auth_token and headers.get("Authorization"):
+            return
+        if isinstance(custom_headers.get("Authorization"), Omit):
+            return
+
+        raise TypeError(
+            '"Could not resolve authentication method. Expected either api_key or auth_token to be set. Or for one of the `X-Api-Key` or `Authorization` headers to be explicitly omitted"'
+        )
+
+    def copy(
+        self,
+        *,
+        api_key: str | None = None,
+        auth_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
+        http_client: httpx.Client | None = None,
+        max_retries: int | NotGiven = NOT_GIVEN,
+        default_headers: Mapping[str, str] | None = None,
+        set_default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        set_default_query: Mapping[str, object] | None = None,
+        _extra_kwargs: Mapping[str, Any] = {},
+    ) -> Self:
+        """
+        Create a new client instance re-using the same options given to the current client with optional overriding.
+        """
+        if default_headers is not None and set_default_headers is not None:
+            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")
+
+        if default_query is not None and set_default_query is not None:
+            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")
+
+        headers = self._custom_headers
+        if default_headers is not None:
+            headers = {**headers, **default_headers}
+        elif set_default_headers is not None:
+            headers = set_default_headers
+
+        params = self._custom_query
+        if default_query is not None:
+            params = {**params, **default_query}
+        elif set_default_query is not None:
+            params = set_default_query
+
+        http_client = http_client or self._client
+        return self.__class__(
+            api_key=api_key or self.api_key,
+            auth_token=auth_token or self.auth_token,
+            base_url=base_url or self.base_url,
+            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
+            http_client=http_client,
+            max_retries=max_retries if is_given(max_retries) else self.max_retries,
+            default_headers=headers,
+            default_query=params,
+            **_extra_kwargs,
+        )
+
+    # Alias for `copy` for nicer inline usage, e.g.
+    # client.with_options(timeout=10).foo.create(...)
+    with_options = copy
+
+    @override
+    def _make_status_error(
+        self,
+        err_msg: str,
+        *,
+        body: object,
+        response: httpx.Response,
+    ) -> APIStatusError:
+        if response.status_code == 400:
+            return _exceptions.BadRequestError(err_msg, response=response, body=body)
+
+        if response.status_code == 401:
+            return _exceptions.AuthenticationError(err_msg, response=response, body=body)
+
+        if response.status_code == 403:
+            return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)
+
+        if response.status_code == 404:
+            return _exceptions.NotFoundError(err_msg, response=response, body=body)
+
+        if response.status_code == 409:
+            return _exceptions.ConflictError(err_msg, response=response, body=body)
+
+        if response.status_code == 413:
+            return _exceptions.RequestTooLargeError(err_msg, response=response, body=body)
+
+        if response.status_code == 422:
+            return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)
+
+        if response.status_code == 429:
+            return _exceptions.RateLimitError(err_msg, response=response, body=body)
+
+        if response.status_code == 529:
+            return _exceptions.OverloadedError(err_msg, response=response, body=body)
+
+        if response.status_code >= 500:
+            return _exceptions.InternalServerError(err_msg, response=response, body=body)
+        return APIStatusError(err_msg, response=response, body=body)
+
+
+class AsyncAnthropic(AsyncAPIClient):
+    completions: completions.AsyncCompletions
+    messages: messages.AsyncMessages
+    models: models.AsyncModels
+    beta: beta.AsyncBeta
+    with_raw_response: AsyncAnthropicWithRawResponse
+    with_streaming_response: AsyncAnthropicWithStreamedResponse
+
+    # client options
+    api_key: str | None
+    auth_token: str | None
+
+    # constants
+    HUMAN_PROMPT = _constants.HUMAN_PROMPT
+    AI_PROMPT = _constants.AI_PROMPT
+
+    def __init__(
+        self,
+        *,
+        api_key: str | None = None,
+        auth_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        # Configure a custom httpx client.
+        # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`.
+        # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details.
+        http_client: httpx.AsyncClient | None = None,
+        # Enable or disable schema validation for data returned by the API.
+        # When enabled an error APIResponseValidationError is raised
+        # if the API responds with invalid data for the expected schema.
+        #
+        # This parameter may be removed or changed in the future.
+        # If you rely on this feature, please open a GitHub issue
+        # outlining your use-case to help us decide if it should be
+        # part of our public interface in the future.
+        _strict_response_validation: bool = False,
+    ) -> None:
+        """Construct a new async AsyncAnthropic client instance.
+
+        This automatically infers the following arguments from their corresponding environment variables if they are not provided:
+        - `api_key` from `ANTHROPIC_API_KEY`
+        - `auth_token` from `ANTHROPIC_AUTH_TOKEN`
+        """
+        if api_key is None:
+            api_key = os.environ.get("ANTHROPIC_API_KEY")
+        self.api_key = api_key
+
+        if auth_token is None:
+            auth_token = os.environ.get("ANTHROPIC_AUTH_TOKEN")
+        self.auth_token = auth_token
+
+        if base_url is None:
+            base_url = os.environ.get("ANTHROPIC_BASE_URL")
+        if base_url is None:
+            base_url = f"https://api.anthropic.com"
+
+        super().__init__(
+            version=__version__,
+            base_url=base_url,
+            max_retries=max_retries,
+            timeout=timeout,
+            http_client=http_client,
+            custom_headers=default_headers,
+            custom_query=default_query,
+            _strict_response_validation=_strict_response_validation,
+        )
+
+        self._default_stream_cls = AsyncStream
+
+        self.completions = completions.AsyncCompletions(self)
+        self.messages = messages.AsyncMessages(self)
+        self.models = models.AsyncModels(self)
+        self.beta = beta.AsyncBeta(self)
+        self.with_raw_response = AsyncAnthropicWithRawResponse(self)
+        self.with_streaming_response = AsyncAnthropicWithStreamedResponse(self)
+
+    @property
+    @override
+    def qs(self) -> Querystring:
+        return Querystring(array_format="comma")
+
+    @property
+    @override
+    def auth_headers(self) -> dict[str, str]:
+        if self._api_key_auth:
+            return self._api_key_auth
+        if self._bearer_auth:
+            return self._bearer_auth
+        return {}
+
+    @property
+    def _api_key_auth(self) -> dict[str, str]:
+        api_key = self.api_key
+        if api_key is None:
+            return {}
+        return {"X-Api-Key": api_key}
+
+    @property
+    def _bearer_auth(self) -> dict[str, str]:
+        auth_token = self.auth_token
+        if auth_token is None:
+            return {}
+        return {"Authorization": f"Bearer {auth_token}"}
+
+    @property
+    @override
+    def default_headers(self) -> dict[str, str | Omit]:
+        return {
+            **super().default_headers,
+            "X-Stainless-Async": f"async:{get_async_library()}",
+            "anthropic-version": "2023-06-01",
+            **self._custom_headers,
+        }
+
+    @override
+    def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None:
+        if self.api_key and headers.get("X-Api-Key"):
+            return
+        if isinstance(custom_headers.get("X-Api-Key"), Omit):
+            return
+
+        if self.auth_token and headers.get("Authorization"):
+            return
+        if isinstance(custom_headers.get("Authorization"), Omit):
+            return
+
+        raise TypeError(
+            '"Could not resolve authentication method. Expected either api_key or auth_token to be set. Or for one of the `X-Api-Key` or `Authorization` headers to be explicitly omitted"'
+        )
+
+    def copy(
+        self,
+        *,
+        api_key: str | None = None,
+        auth_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
+        http_client: httpx.AsyncClient | None = None,
+        max_retries: int | NotGiven = NOT_GIVEN,
+        default_headers: Mapping[str, str] | None = None,
+        set_default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        set_default_query: Mapping[str, object] | None = None,
+        _extra_kwargs: Mapping[str, Any] = {},
+    ) -> Self:
+        """
+        Create a new client instance re-using the same options given to the current client with optional overriding.
+        """
+        if default_headers is not None and set_default_headers is not None:
+            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")
+
+        if default_query is not None and set_default_query is not None:
+            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")
+
+        headers = self._custom_headers
+        if default_headers is not None:
+            headers = {**headers, **default_headers}
+        elif set_default_headers is not None:
+            headers = set_default_headers
+
+        params = self._custom_query
+        if default_query is not None:
+            params = {**params, **default_query}
+        elif set_default_query is not None:
+            params = set_default_query
+
+        http_client = http_client or self._client
+        return self.__class__(
+            api_key=api_key or self.api_key,
+            auth_token=auth_token or self.auth_token,
+            base_url=base_url or self.base_url,
+            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
+            http_client=http_client,
+            max_retries=max_retries if is_given(max_retries) else self.max_retries,
+            default_headers=headers,
+            default_query=params,
+            **_extra_kwargs,
+        )
+
+    # Alias for `copy` for nicer inline usage, e.g.
+    # client.with_options(timeout=10).foo.create(...)
+    with_options = copy
+
+    @override
+    def _make_status_error(
+        self,
+        err_msg: str,
+        *,
+        body: object,
+        response: httpx.Response,
+    ) -> APIStatusError:
+        if response.status_code == 400:
+            return _exceptions.BadRequestError(err_msg, response=response, body=body)
+
+        if response.status_code == 401:
+            return _exceptions.AuthenticationError(err_msg, response=response, body=body)
+
+        if response.status_code == 403:
+            return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)
+
+        if response.status_code == 404:
+            return _exceptions.NotFoundError(err_msg, response=response, body=body)
+
+        if response.status_code == 409:
+            return _exceptions.ConflictError(err_msg, response=response, body=body)
+
+        if response.status_code == 422:
+            return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)
+
+        if response.status_code == 429:
+            return _exceptions.RateLimitError(err_msg, response=response, body=body)
+
+        if response.status_code >= 500:
+            return _exceptions.InternalServerError(err_msg, response=response, body=body)
+        return APIStatusError(err_msg, response=response, body=body)
+
+
+class AnthropicWithRawResponse:
+    def __init__(self, client: Anthropic) -> None:
+        self.completions = completions.CompletionsWithRawResponse(client.completions)
+        self.messages = messages.MessagesWithRawResponse(client.messages)
+        self.models = models.ModelsWithRawResponse(client.models)
+        self.beta = beta.BetaWithRawResponse(client.beta)
+
+
+class AsyncAnthropicWithRawResponse:
+    def __init__(self, client: AsyncAnthropic) -> None:
+        self.completions = completions.AsyncCompletionsWithRawResponse(client.completions)
+        self.messages = messages.AsyncMessagesWithRawResponse(client.messages)
+        self.models = models.AsyncModelsWithRawResponse(client.models)
+        self.beta = beta.AsyncBetaWithRawResponse(client.beta)
+
+
+class AnthropicWithStreamedResponse:
+    def __init__(self, client: Anthropic) -> None:
+        self.completions = completions.CompletionsWithStreamingResponse(client.completions)
+        self.messages = messages.MessagesWithStreamingResponse(client.messages)
+        self.models = models.ModelsWithStreamingResponse(client.models)
+        self.beta = beta.BetaWithStreamingResponse(client.beta)
+
+
+class AsyncAnthropicWithStreamedResponse:
+    def __init__(self, client: AsyncAnthropic) -> None:
+        self.completions = completions.AsyncCompletionsWithStreamingResponse(client.completions)
+        self.messages = messages.AsyncMessagesWithStreamingResponse(client.messages)
+        self.models = models.AsyncModelsWithStreamingResponse(client.models)
+        self.beta = beta.AsyncBetaWithStreamingResponse(client.beta)
+
+
+Client = Anthropic
+
+AsyncClient = AsyncAnthropic
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_compat.py b/.venv/lib/python3.12/site-packages/anthropic/_compat.py
new file mode 100644
index 00000000..92d9ee61
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_compat.py
@@ -0,0 +1,219 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload
+from datetime import date, datetime
+from typing_extensions import Self, Literal
+
+import pydantic
+from pydantic.fields import FieldInfo
+
+from ._types import IncEx, StrBytesIntFloat
+
+_T = TypeVar("_T")
+_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel)
+
+# --------------- Pydantic v2 compatibility ---------------
+
+# Pyright incorrectly reports some of our functions as overriding a method when they don't
+# pyright: reportIncompatibleMethodOverride=false
+
+PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
+
+# v1 re-exports
+if TYPE_CHECKING:
+
+    def parse_date(value: date | StrBytesIntFloat) -> date:  # noqa: ARG001
+        ...
+
+    def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime:  # noqa: ARG001
+        ...
+
+    def get_args(t: type[Any]) -> tuple[Any, ...]:  # noqa: ARG001
+        ...
+
+    def is_union(tp: type[Any] | None) -> bool:  # noqa: ARG001
+        ...
+
+    def get_origin(t: type[Any]) -> type[Any] | None:  # noqa: ARG001
+        ...
+
+    def is_literal_type(type_: type[Any]) -> bool:  # noqa: ARG001
+        ...
+
+    def is_typeddict(type_: type[Any]) -> bool:  # noqa: ARG001
+        ...
+
+else:
+    if PYDANTIC_V2:
+        from pydantic.v1.typing import (
+            get_args as get_args,
+            is_union as is_union,
+            get_origin as get_origin,
+            is_typeddict as is_typeddict,
+            is_literal_type as is_literal_type,
+        )
+        from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
+    else:
+        from pydantic.typing import (
+            get_args as get_args,
+            is_union as is_union,
+            get_origin as get_origin,
+            is_typeddict as is_typeddict,
+            is_literal_type as is_literal_type,
+        )
+        from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
+
+
+# refactored config
+if TYPE_CHECKING:
+    from pydantic import ConfigDict as ConfigDict
+else:
+    if PYDANTIC_V2:
+        from pydantic import ConfigDict
+    else:
+        # TODO: provide an error message here?
+        ConfigDict = None
+
+
+# renamed methods / properties
+def parse_obj(model: type[_ModelT], value: object) -> _ModelT:
+    if PYDANTIC_V2:
+        return model.model_validate(value)
+    else:
+        return cast(_ModelT, model.parse_obj(value))  # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
+
+
+def field_is_required(field: FieldInfo) -> bool:
+    if PYDANTIC_V2:
+        return field.is_required()
+    return field.required  # type: ignore
+
+
+def field_get_default(field: FieldInfo) -> Any:
+    value = field.get_default()
+    if PYDANTIC_V2:
+        from pydantic_core import PydanticUndefined
+
+        if value == PydanticUndefined:
+            return None
+        return value
+    return value
+
+
+def field_outer_type(field: FieldInfo) -> Any:
+    if PYDANTIC_V2:
+        return field.annotation
+    return field.outer_type_  # type: ignore
+
+
+def get_model_config(model: type[pydantic.BaseModel]) -> Any:
+    if PYDANTIC_V2:
+        return model.model_config
+    return model.__config__  # type: ignore
+
+
+def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]:
+    if PYDANTIC_V2:
+        return model.model_fields
+    return model.__fields__  # type: ignore
+
+
+def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT:
+    if PYDANTIC_V2:
+        return model.model_copy(deep=deep)
+    return model.copy(deep=deep)  # type: ignore
+
+
+def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str:
+    if PYDANTIC_V2:
+        return model.model_dump_json(indent=indent)
+    return model.json(indent=indent)  # type: ignore
+
+
+def model_dump(
+    model: pydantic.BaseModel,
+    *,
+    exclude: IncEx | None = None,
+    exclude_unset: bool = False,
+    exclude_defaults: bool = False,
+    warnings: bool = True,
+    mode: Literal["json", "python"] = "python",
+) -> dict[str, Any]:
+    if PYDANTIC_V2 or hasattr(model, "model_dump"):
+        return model.model_dump(
+            mode=mode,
+            exclude=exclude,
+            exclude_unset=exclude_unset,
+            exclude_defaults=exclude_defaults,
+            # warnings are not supported in Pydantic v1
+            warnings=warnings if PYDANTIC_V2 else True,
+        )
+    return cast(
+        "dict[str, Any]",
+        model.dict(  # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
+            exclude=exclude,
+            exclude_unset=exclude_unset,
+            exclude_defaults=exclude_defaults,
+        ),
+    )
+
+
+def model_parse(model: type[_ModelT], data: Any) -> _ModelT:
+    if PYDANTIC_V2:
+        return model.model_validate(data)
+    return model.parse_obj(data)  # pyright: ignore[reportDeprecated]
+
+
+# generic models
+if TYPE_CHECKING:
+
+    class GenericModel(pydantic.BaseModel): ...
+
+else:
+    if PYDANTIC_V2:
+        # there no longer needs to be a distinction in v2 but
+        # we still have to create our own subclass to avoid
+        # inconsistent MRO ordering errors
+        class GenericModel(pydantic.BaseModel): ...
+
+    else:
+        import pydantic.generics
+
+        class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ...
+
+
+# cached properties
+if TYPE_CHECKING:
+    cached_property = property
+
+    # we define a separate type (copied from typeshed)
+    # that represents that `cached_property` is `set`able
+    # at runtime, which differs from `@property`.
+    #
+    # this is a separate type as editors likely special case
+    # `@property` and we don't want to cause issues just to have
+    # more helpful internal types.
+
+    class typed_cached_property(Generic[_T]):
+        func: Callable[[Any], _T]
+        attrname: str | None
+
+        def __init__(self, func: Callable[[Any], _T]) -> None: ...
+
+        @overload
+        def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ...
+
+        @overload
+        def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ...
+
+        def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self:
+            raise NotImplementedError()
+
+        def __set_name__(self, owner: type[Any], name: str) -> None: ...
+
+        # __set__ is not defined at runtime, but @cached_property is designed to be settable
+        def __set__(self, instance: object, value: _T) -> None: ...
+else:
+    from functools import cached_property as cached_property
+
+    typed_cached_property = cached_property
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_constants.py b/.venv/lib/python3.12/site-packages/anthropic/_constants.py
new file mode 100644
index 00000000..617c4b47
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_constants.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import httpx
+
+RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response"
+OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to"
+
+# default timeout is 10 minutes
+DEFAULT_TIMEOUT = httpx.Timeout(timeout=10 * 60, connect=5.0)
+DEFAULT_MAX_RETRIES = 2
+DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=1000, max_keepalive_connections=100)
+
+INITIAL_RETRY_DELAY = 0.5
+MAX_RETRY_DELAY = 8.0
+
+HUMAN_PROMPT = "\n\nHuman:"
+
+AI_PROMPT = "\n\nAssistant:"
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_decoders/jsonl.py b/.venv/lib/python3.12/site-packages/anthropic/_decoders/jsonl.py
new file mode 100644
index 00000000..ac5ac74f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_decoders/jsonl.py
@@ -0,0 +1,123 @@
+from __future__ import annotations
+
+import json
+from typing_extensions import Generic, TypeVar, Iterator, AsyncIterator
+
+import httpx
+
+from .._models import construct_type_unchecked
+
+_T = TypeVar("_T")
+
+
+class JSONLDecoder(Generic[_T]):
+    """A decoder for [JSON Lines](https://jsonlines.org) format.
+
+    This class provides an iterator over a byte-iterator that parses each JSON Line
+    into a given type.
+    """
+
+    http_response: httpx.Response
+    """The HTTP response this decoder was constructed from"""
+
+    def __init__(
+        self,
+        *,
+        raw_iterator: Iterator[bytes],
+        line_type: type[_T],
+        http_response: httpx.Response,
+    ) -> None:
+        super().__init__()
+        self.http_response = http_response
+        self._raw_iterator = raw_iterator
+        self._line_type = line_type
+        self._iterator = self.__decode__()
+
+    def close(self) -> None:
+        """Close the response body stream.
+
+        This is called automatically if you consume the entire stream.
+        """
+        self.http_response.close()
+
+    def __decode__(self) -> Iterator[_T]:
+        buf = b""
+        for chunk in self._raw_iterator:
+            for line in chunk.splitlines(keepends=True):
+                buf += line
+                if buf.endswith((b"\r", b"\n", b"\r\n")):
+                    yield construct_type_unchecked(
+                        value=json.loads(buf),
+                        type_=self._line_type,
+                    )
+                    buf = b""
+
+        # flush
+        if buf:
+            yield construct_type_unchecked(
+                value=json.loads(buf),
+                type_=self._line_type,
+            )
+
+    def __next__(self) -> _T:
+        return self._iterator.__next__()
+
+    def __iter__(self) -> Iterator[_T]:
+        for item in self._iterator:
+            yield item
+
+
+class AsyncJSONLDecoder(Generic[_T]):
+    """A decoder for [JSON Lines](https://jsonlines.org) format.
+
+    This class provides an async iterator over a byte-iterator that parses each JSON Line
+    into a given type.
+    """
+
+    http_response: httpx.Response
+
+    def __init__(
+        self,
+        *,
+        raw_iterator: AsyncIterator[bytes],
+        line_type: type[_T],
+        http_response: httpx.Response,
+    ) -> None:
+        super().__init__()
+        self.http_response = http_response
+        self._raw_iterator = raw_iterator
+        self._line_type = line_type
+        self._iterator = self.__decode__()
+
+    async def close(self) -> None:
+        """Close the response body stream.
+
+        This is called automatically if you consume the entire stream.
+        """
+        await self.http_response.aclose()
+
+    async def __decode__(self) -> AsyncIterator[_T]:
+        buf = b""
+        async for chunk in self._raw_iterator:
+            for line in chunk.splitlines(keepends=True):
+                buf += line
+                if buf.endswith((b"\r", b"\n", b"\r\n")):
+                    yield construct_type_unchecked(
+                        value=json.loads(buf),
+                        type_=self._line_type,
+                    )
+                    buf = b""
+
+        # flush
+        if buf:
+            yield construct_type_unchecked(
+                value=json.loads(buf),
+                type_=self._line_type,
+            )
+
+    async def __anext__(self) -> _T:
+        return await self._iterator.__anext__()
+
+    async def __aiter__(self) -> AsyncIterator[_T]:
+        async for item in self._iterator:
+            yield item
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_exceptions.py b/.venv/lib/python3.12/site-packages/anthropic/_exceptions.py
new file mode 100644
index 00000000..2bf3e81a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_exceptions.py
@@ -0,0 +1,126 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+__all__ = [
+    "BadRequestError",
+    "AuthenticationError",
+    "PermissionDeniedError",
+    "NotFoundError",
+    "ConflictError",
+    "UnprocessableEntityError",
+    "RateLimitError",
+    "InternalServerError",
+]
+
+
+class AnthropicError(Exception):
+    pass
+
+
+class APIError(AnthropicError):
+    message: str
+    request: httpx.Request
+
+    body: object | None
+    """The API response body.
+
+    If the API responded with a valid JSON structure then this property will be the
+    decoded result.
+
+    If it isn't a valid JSON structure then this will be the raw response.
+
+    If there was no response associated with this error then it will be `None`.
+    """
+
+    def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None:  # noqa: ARG002
+        super().__init__(message)
+        self.request = request
+        self.message = message
+        self.body = body
+
+
+class APIResponseValidationError(APIError):
+    response: httpx.Response
+    status_code: int
+
+    def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None:
+        super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body)
+        self.response = response
+        self.status_code = response.status_code
+
+
+class APIStatusError(APIError):
+    """Raised when an API response has a status code of 4xx or 5xx."""
+
+    response: httpx.Response
+    status_code: int
+    request_id: str | None
+
+    def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None:
+        super().__init__(message, response.request, body=body)
+        self.response = response
+        self.status_code = response.status_code
+        self.request_id = response.headers.get("request-id")
+
+
+class APIConnectionError(APIError):
+    def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None:
+        super().__init__(message, request, body=None)
+
+
+class APITimeoutError(APIConnectionError):
+    def __init__(self, request: httpx.Request) -> None:
+        super().__init__(message="Request timed out.", request=request)
+
+
+class BadRequestError(APIStatusError):
+    status_code: Literal[400] = 400  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class AuthenticationError(APIStatusError):
+    status_code: Literal[401] = 401  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class PermissionDeniedError(APIStatusError):
+    status_code: Literal[403] = 403  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class NotFoundError(APIStatusError):
+    status_code: Literal[404] = 404  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class ConflictError(APIStatusError):
+    status_code: Literal[409] = 409  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class RequestTooLargeError(APIStatusError):
+    status_code: Literal[413] = 413  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class UnprocessableEntityError(APIStatusError):
+    status_code: Literal[422] = 422  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class RateLimitError(APIStatusError):
+    status_code: Literal[429] = 429  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class ServiceUnavailableError(APIStatusError):
+    status_code: Literal[503] = 503  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class OverloadedError(APIStatusError):
+    status_code: Literal[529] = 529  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class DeadlineExceededError(APIStatusError):
+    status_code: Literal[504] = 504  # pyright: ignore[reportIncompatibleVariableOverride]
+
+
+class InternalServerError(APIStatusError):
+    pass
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_files.py b/.venv/lib/python3.12/site-packages/anthropic/_files.py
new file mode 100644
index 00000000..715cc207
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_files.py
@@ -0,0 +1,123 @@
+from __future__ import annotations
+
+import io
+import os
+import pathlib
+from typing import overload
+from typing_extensions import TypeGuard
+
+import anyio
+
+from ._types import (
+    FileTypes,
+    FileContent,
+    RequestFiles,
+    HttpxFileTypes,
+    Base64FileInput,
+    HttpxFileContent,
+    HttpxRequestFiles,
+)
+from ._utils import is_tuple_t, is_mapping_t, is_sequence_t
+
+
+def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]:
+    return isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike)
+
+
+def is_file_content(obj: object) -> TypeGuard[FileContent]:
+    return (
+        isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike)
+    )
+
+
+def assert_is_file_content(obj: object, *, key: str | None = None) -> None:
+    if not is_file_content(obj):
+        prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`"
+        raise RuntimeError(
+            f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead."
+        ) from None
+
+
+@overload
+def to_httpx_files(files: None) -> None: ...
+
+
+@overload
+def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ...
+
+
+def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None:
+    if files is None:
+        return None
+
+    if is_mapping_t(files):
+        files = {key: _transform_file(file) for key, file in files.items()}
+    elif is_sequence_t(files):
+        files = [(key, _transform_file(file)) for key, file in files]
+    else:
+        raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence")
+
+    return files
+
+
+def _transform_file(file: FileTypes) -> HttpxFileTypes:
+    if is_file_content(file):
+        if isinstance(file, os.PathLike):
+            path = pathlib.Path(file)
+            return (path.name, path.read_bytes())
+
+        return file
+
+    if is_tuple_t(file):
+        return (file[0], _read_file_content(file[1]), *file[2:])
+
+    raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple")
+
+
+def _read_file_content(file: FileContent) -> HttpxFileContent:
+    if isinstance(file, os.PathLike):
+        return pathlib.Path(file).read_bytes()
+    return file
+
+
+@overload
+async def async_to_httpx_files(files: None) -> None: ...
+
+
+@overload
+async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ...
+
+
+async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None:
+    if files is None:
+        return None
+
+    if is_mapping_t(files):
+        files = {key: await _async_transform_file(file) for key, file in files.items()}
+    elif is_sequence_t(files):
+        files = [(key, await _async_transform_file(file)) for key, file in files]
+    else:
+        raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence")
+
+    return files
+
+
+async def _async_transform_file(file: FileTypes) -> HttpxFileTypes:
+    if is_file_content(file):
+        if isinstance(file, os.PathLike):
+            path = anyio.Path(file)
+            return (path.name, await path.read_bytes())
+
+        return file
+
+    if is_tuple_t(file):
+        return (file[0], await _async_read_file_content(file[1]), *file[2:])
+
+    raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple")
+
+
+async def _async_read_file_content(file: FileContent) -> HttpxFileContent:
+    if isinstance(file, os.PathLike):
+        return await anyio.Path(file).read_bytes()
+
+    return file
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_legacy_response.py b/.venv/lib/python3.12/site-packages/anthropic/_legacy_response.py
new file mode 100644
index 00000000..5703932e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_legacy_response.py
@@ -0,0 +1,511 @@
+from __future__ import annotations
+
+import os
+import inspect
+import logging
+import datetime
+import functools
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    Union,
+    Generic,
+    TypeVar,
+    Callable,
+    Iterator,
+    AsyncIterator,
+    cast,
+    overload,
+)
+from typing_extensions import Awaitable, ParamSpec, override, deprecated, get_origin
+
+import anyio
+import httpx
+import pydantic
+
+from ._types import NoneType
+from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type
+from ._models import BaseModel, is_basemodel, add_request_id
+from ._constants import RAW_RESPONSE_HEADER
+from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type
+from ._exceptions import APIResponseValidationError
+from ._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder
+
+if TYPE_CHECKING:
+    from ._models import FinalRequestOptions
+    from ._base_client import BaseClient
+
+
+P = ParamSpec("P")
+R = TypeVar("R")
+_T = TypeVar("_T")
+_T_co = TypeVar("_T_co", covariant=True)
+
+log: logging.Logger = logging.getLogger(__name__)
+
+
+class LegacyAPIResponse(Generic[R]):
+    """This is a legacy class as it will be replaced by `APIResponse`
+    and `AsyncAPIResponse` in the `_response.py` file in the next major
+    release.
+
+    For the sync client this will mostly be the same with the exception
+    of `content` & `text` will be methods instead of properties. In the
+    async client, all methods will be async.
+
+    A migration script will be provided & the migration in general should
+    be smooth.
+    """
+
+    _cast_to: type[R]
+    _client: BaseClient[Any, Any]
+    _parsed_by_type: dict[type[Any], Any]
+    _stream: bool
+    _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None
+    _options: FinalRequestOptions
+
+    http_response: httpx.Response
+
+    retries_taken: int
+    """The number of retries made. If no retries happened this will be `0`"""
+
+    def __init__(
+        self,
+        *,
+        raw: httpx.Response,
+        cast_to: type[R],
+        client: BaseClient[Any, Any],
+        stream: bool,
+        stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
+        options: FinalRequestOptions,
+        retries_taken: int = 0,
+    ) -> None:
+        self._cast_to = cast_to
+        self._client = client
+        self._parsed_by_type = {}
+        self._stream = stream
+        self._stream_cls = stream_cls
+        self._options = options
+        self.http_response = raw
+        self.retries_taken = retries_taken
+
+    @property
+    def request_id(self) -> str | None:
+        return self.http_response.headers.get("request-id")  # type: ignore[no-any-return]
+
+    @overload
+    def parse(self, *, to: type[_T]) -> _T: ...
+
+    @overload
+    def parse(self) -> R: ...
+
+    def parse(self, *, to: type[_T] | None = None) -> R | _T:
+        """Returns the rich python representation of this response's data.
+
+        NOTE: For the async client: this will become a coroutine in the next major version.
+
+        For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`.
+
+        You can customise the type that the response is parsed into through
+        the `to` argument, e.g.
+
+        ```py
+        from anthropic import BaseModel
+
+
+        class MyModel(BaseModel):
+            foo: str
+
+
+        obj = response.parse(to=MyModel)
+        print(obj.foo)
+        ```
+
+        We support parsing:
+          - `BaseModel`
+          - `dict`
+          - `list`
+          - `Union`
+          - `str`
+          - `int`
+          - `float`
+          - `httpx.Response`
+        """
+        cache_key = to if to is not None else self._cast_to
+        cached = self._parsed_by_type.get(cache_key)
+        if cached is not None:
+            return cached  # type: ignore[no-any-return]
+
+        parsed = self._parse(to=to)
+        if is_given(self._options.post_parser):
+            parsed = self._options.post_parser(parsed)
+
+        if isinstance(parsed, BaseModel):
+            add_request_id(parsed, self.request_id)
+
+        self._parsed_by_type[cache_key] = parsed
+        return cast(R, parsed)
+
+    @property
+    def headers(self) -> httpx.Headers:
+        return self.http_response.headers
+
+    @property
+    def http_request(self) -> httpx.Request:
+        return self.http_response.request
+
+    @property
+    def status_code(self) -> int:
+        return self.http_response.status_code
+
+    @property
+    def url(self) -> httpx.URL:
+        return self.http_response.url
+
+    @property
+    def method(self) -> str:
+        return self.http_request.method
+
+    @property
+    def content(self) -> bytes:
+        """Return the binary response content.
+
+        NOTE: this will be removed in favour of `.read()` in the
+        next major version.
+        """
+        return self.http_response.content
+
+    @property
+    def text(self) -> str:
+        """Return the decoded response content.
+
+        NOTE: this will be turned into a method in the next major version.
+        """
+        return self.http_response.text
+
+    @property
+    def http_version(self) -> str:
+        return self.http_response.http_version
+
+    @property
+    def is_closed(self) -> bool:
+        return self.http_response.is_closed
+
+    @property
+    def elapsed(self) -> datetime.timedelta:
+        """The time taken for the complete request/response cycle to complete."""
+        return self.http_response.elapsed
+
+    def _parse(self, *, to: type[_T] | None = None) -> R | _T:
+        cast_to = to if to is not None else self._cast_to
+
+        # unwrap `TypeAlias('Name', T)` -> `T`
+        if is_type_alias_type(cast_to):
+            cast_to = cast_to.__value__  # type: ignore[unreachable]
+
+        # unwrap `Annotated[T, ...]` -> `T`
+        if cast_to and is_annotated_type(cast_to):
+            cast_to = extract_type_arg(cast_to, 0)
+
+        origin = get_origin(cast_to) or cast_to
+
+        if inspect.isclass(origin):
+            if issubclass(cast(Any, origin), JSONLDecoder):
+                return cast(
+                    R,
+                    cast("type[JSONLDecoder[Any]]", cast_to)(
+                        raw_iterator=self.http_response.iter_bytes(chunk_size=64),
+                        line_type=extract_type_arg(cast_to, 0),
+                        http_response=self.http_response,
+                    ),
+                )
+
+            if issubclass(cast(Any, origin), AsyncJSONLDecoder):
+                return cast(
+                    R,
+                    cast("type[AsyncJSONLDecoder[Any]]", cast_to)(
+                        raw_iterator=self.http_response.aiter_bytes(chunk_size=64),
+                        line_type=extract_type_arg(cast_to, 0),
+                        http_response=self.http_response,
+                    ),
+                )
+
+        if self._stream:
+            if to:
+                if not is_stream_class_type(to):
+                    raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}")
+
+                return cast(
+                    _T,
+                    to(
+                        cast_to=extract_stream_chunk_type(
+                            to,
+                            failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]",
+                        ),
+                        response=self.http_response,
+                        client=cast(Any, self._client),
+                    ),
+                )
+
+            if self._stream_cls:
+                return cast(
+                    R,
+                    self._stream_cls(
+                        cast_to=extract_stream_chunk_type(self._stream_cls),
+                        response=self.http_response,
+                        client=cast(Any, self._client),
+                    ),
+                )
+
+            stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls)
+            if stream_cls is None:
+                raise MissingStreamClassError()
+
+            return cast(
+                R,
+                stream_cls(
+                    cast_to=cast_to,
+                    response=self.http_response,
+                    client=cast(Any, self._client),
+                ),
+            )
+
+        if cast_to is NoneType:
+            return cast(R, None)
+
+        response = self.http_response
+        if cast_to == str:
+            return cast(R, response.text)
+
+        if cast_to == int:
+            return cast(R, int(response.text))
+
+        if cast_to == float:
+            return cast(R, float(response.text))
+
+        if cast_to == bool:
+            return cast(R, response.text.lower() == "true")
+
+        if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent):
+            return cast(R, cast_to(response))  # type: ignore
+
+        if origin == LegacyAPIResponse:
+            raise RuntimeError("Unexpected state - cast_to is `APIResponse`")
+
+        if inspect.isclass(
+            origin  # pyright: ignore[reportUnknownArgumentType]
+        ) and issubclass(origin, httpx.Response):
+            # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response
+            # and pass that class to our request functions. We cannot change the variance to be either
+            # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct
+            # the response class ourselves but that is something that should be supported directly in httpx
+            # as it would be easy to incorrectly construct the Response object due to the multitude of arguments.
+            if cast_to != httpx.Response:
+                raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`")
+            return cast(R, response)
+
+        if (
+            inspect.isclass(
+                origin  # pyright: ignore[reportUnknownArgumentType]
+            )
+            and not issubclass(origin, BaseModel)
+            and issubclass(origin, pydantic.BaseModel)
+        ):
+            raise TypeError("Pydantic models must subclass our base model type, e.g. `from anthropic import BaseModel`")
+
+        if (
+            cast_to is not object
+            and not origin is list
+            and not origin is dict
+            and not origin is Union
+            and not issubclass(origin, BaseModel)
+        ):
+            raise RuntimeError(
+                f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}."
+            )
+
+        # split is required to handle cases where additional information is included
+        # in the response, e.g. application/json; charset=utf-8
+        content_type, *_ = response.headers.get("content-type", "*").split(";")
+        if content_type != "application/json":
+            if is_basemodel(cast_to):
+                try:
+                    data = response.json()
+                except Exception as exc:
+                    log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc)
+                else:
+                    return self._client._process_response_data(
+                        data=data,
+                        cast_to=cast_to,  # type: ignore
+                        response=response,
+                    )
+
+            if self._client._strict_response_validation:
+                raise APIResponseValidationError(
+                    response=response,
+                    message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.",
+                    body=response.text,
+                )
+
+            # If the API responds with content that isn't JSON then we just return
+            # the (decoded) text without performing any parsing so that you can still
+            # handle the response however you need to.
+            return response.text  # type: ignore
+
+        data = response.json()
+
+        return self._client._process_response_data(
+            data=data,
+            cast_to=cast_to,  # type: ignore
+            response=response,
+        )
+
+    @override
+    def __repr__(self) -> str:
+        return f"<APIResponse [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>"
+
+
+class MissingStreamClassError(TypeError):
+    def __init__(self) -> None:
+        super().__init__(
+            "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `anthropic._streaming` for reference",
+        )
+
+
+def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, LegacyAPIResponse[R]]:
+    """Higher order function that takes one of our bound API methods and wraps it
+    to support returning the raw `APIResponse` object directly.
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]:
+        extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "true"
+
+        kwargs["extra_headers"] = extra_headers
+
+        return cast(LegacyAPIResponse[R], func(*args, **kwargs))
+
+    return wrapped
+
+
+def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[LegacyAPIResponse[R]]]:
+    """Higher order function that takes one of our bound API methods and wraps it
+    to support returning the raw `APIResponse` object directly.
+    """
+
+    @functools.wraps(func)
+    async def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]:
+        extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "true"
+
+        kwargs["extra_headers"] = extra_headers
+
+        return cast(LegacyAPIResponse[R], await func(*args, **kwargs))
+
+    return wrapped
+
+
+class HttpxBinaryResponseContent:
+    response: httpx.Response
+
+    def __init__(self, response: httpx.Response) -> None:
+        self.response = response
+
+    @property
+    def content(self) -> bytes:
+        return self.response.content
+
+    @property
+    def text(self) -> str:
+        return self.response.text
+
+    @property
+    def encoding(self) -> str | None:
+        return self.response.encoding
+
+    @property
+    def charset_encoding(self) -> str | None:
+        return self.response.charset_encoding
+
+    def json(self, **kwargs: Any) -> Any:
+        return self.response.json(**kwargs)
+
+    def read(self) -> bytes:
+        return self.response.read()
+
+    def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]:
+        return self.response.iter_bytes(chunk_size)
+
+    def iter_text(self, chunk_size: int | None = None) -> Iterator[str]:
+        return self.response.iter_text(chunk_size)
+
+    def iter_lines(self) -> Iterator[str]:
+        return self.response.iter_lines()
+
+    def iter_raw(self, chunk_size: int | None = None) -> Iterator[bytes]:
+        return self.response.iter_raw(chunk_size)
+
+    def write_to_file(
+        self,
+        file: str | os.PathLike[str],
+    ) -> None:
+        """Write the output to the given file.
+
+        Accepts a filename or any path-like object, e.g. pathlib.Path
+
+        Note: if you want to stream the data to the file instead of writing
+        all at once then you should use `.with_streaming_response` when making
+        the API request, e.g. `client.with_streaming_response.foo().stream_to_file('my_filename.txt')`
+        """
+        with open(file, mode="wb") as f:
+            for data in self.response.iter_bytes():
+                f.write(data)
+
+    @deprecated(
+        "Due to a bug, this method doesn't actually stream the response content, `.with_streaming_response.method()` should be used instead"
+    )
+    def stream_to_file(
+        self,
+        file: str | os.PathLike[str],
+        *,
+        chunk_size: int | None = None,
+    ) -> None:
+        with open(file, mode="wb") as f:
+            for data in self.response.iter_bytes(chunk_size):
+                f.write(data)
+
+    def close(self) -> None:
+        return self.response.close()
+
+    async def aread(self) -> bytes:
+        return await self.response.aread()
+
+    async def aiter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]:
+        return self.response.aiter_bytes(chunk_size)
+
+    async def aiter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]:
+        return self.response.aiter_text(chunk_size)
+
+    async def aiter_lines(self) -> AsyncIterator[str]:
+        return self.response.aiter_lines()
+
+    async def aiter_raw(self, chunk_size: int | None = None) -> AsyncIterator[bytes]:
+        return self.response.aiter_raw(chunk_size)
+
+    @deprecated(
+        "Due to a bug, this method doesn't actually stream the response content, `.with_streaming_response.method()` should be used instead"
+    )
+    async def astream_to_file(
+        self,
+        file: str | os.PathLike[str],
+        *,
+        chunk_size: int | None = None,
+    ) -> None:
+        path = anyio.Path(file)
+        async with await path.open(mode="wb") as f:
+            async for data in self.response.aiter_bytes(chunk_size):
+                await f.write(data)
+
+    async def aclose(self) -> None:
+        return await self.response.aclose()
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_models.py b/.venv/lib/python3.12/site-packages/anthropic/_models.py
new file mode 100644
index 00000000..dad8df9e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_models.py
@@ -0,0 +1,832 @@
+from __future__ import annotations
+
+import os
+import inspect
+from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
+from datetime import date, datetime
+from typing_extensions import (
+    Unpack,
+    Literal,
+    ClassVar,
+    Protocol,
+    Required,
+    ParamSpec,
+    TypedDict,
+    TypeGuard,
+    final,
+    override,
+    runtime_checkable,
+)
+
+import pydantic
+import pydantic.generics
+from pydantic.fields import FieldInfo
+
+from ._types import (
+    Body,
+    IncEx,
+    Query,
+    ModelT,
+    Headers,
+    Timeout,
+    NotGiven,
+    AnyMapping,
+    HttpxRequestFiles,
+)
+from ._utils import (
+    PropertyInfo,
+    is_list,
+    is_given,
+    json_safe,
+    lru_cache,
+    is_mapping,
+    parse_date,
+    coerce_boolean,
+    parse_datetime,
+    strip_not_given,
+    extract_type_arg,
+    is_annotated_type,
+    is_type_alias_type,
+    strip_annotated_type,
+)
+from ._compat import (
+    PYDANTIC_V2,
+    ConfigDict,
+    GenericModel as BaseGenericModel,
+    get_args,
+    is_union,
+    parse_obj,
+    get_origin,
+    is_literal_type,
+    get_model_config,
+    get_model_fields,
+    field_get_default,
+)
+from ._constants import RAW_RESPONSE_HEADER
+
+if TYPE_CHECKING:
+    from pydantic_core.core_schema import ModelField, LiteralSchema, ModelFieldsSchema
+
+__all__ = ["BaseModel", "GenericModel"]
+
+_T = TypeVar("_T")
+_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel")
+
+P = ParamSpec("P")
+
+
+@runtime_checkable
+class _ConfigProtocol(Protocol):
+    allow_population_by_field_name: bool
+
+
+class BaseModel(pydantic.BaseModel):
+    if PYDANTIC_V2:
+        model_config: ClassVar[ConfigDict] = ConfigDict(
+            extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true"))
+        )
+    else:
+
+        @property
+        @override
+        def model_fields_set(self) -> set[str]:
+            # a forwards-compat shim for pydantic v2
+            return self.__fields_set__  # type: ignore
+
+        class Config(pydantic.BaseConfig):  # pyright: ignore[reportDeprecated]
+            extra: Any = pydantic.Extra.allow  # type: ignore
+
+    if TYPE_CHECKING:
+        _request_id: Optional[str] = None
+        """The ID of the request, returned via the `request-id` header. Useful for debugging requests and reporting issues to Anthropic.
+        This will **only** be set for the top-level response object, it will not be defined for nested objects. For example:
+        
+        ```py
+        message = await client.messages.create(...)
+        message._request_id  # req_xxx
+        message.usage._request_id  # raises `AttributeError`
+        ```
+
+        Note: unlike other properties that use an `_` prefix, this property
+        *is* public. Unless documented otherwise, all other `_` prefix properties,
+        methods and modules are *private*.
+        """
+
+    def to_dict(
+        self,
+        *,
+        mode: Literal["json", "python"] = "python",
+        use_api_names: bool = True,
+        exclude_unset: bool = True,
+        exclude_defaults: bool = False,
+        exclude_none: bool = False,
+        warnings: bool = True,
+    ) -> dict[str, object]:
+        """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
+
+        By default, fields that were not set by the API will not be included,
+        and keys will match the API response, *not* the property names from the model.
+
+        For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property,
+        the output will use the `"fooBar"` key (unless `use_api_names=False` is passed).
+
+        Args:
+            mode:
+                If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`.
+                If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)`
+
+            use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`.
+            exclude_unset: Whether to exclude fields that have not been explicitly set.
+            exclude_defaults: Whether to exclude fields that are set to their default value from the output.
+            exclude_none: Whether to exclude fields that have a value of `None` from the output.
+            warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2.
+        """
+        return self.model_dump(
+            mode=mode,
+            by_alias=use_api_names,
+            exclude_unset=exclude_unset,
+            exclude_defaults=exclude_defaults,
+            exclude_none=exclude_none,
+            warnings=warnings,
+        )
+
+    def to_json(
+        self,
+        *,
+        indent: int | None = 2,
+        use_api_names: bool = True,
+        exclude_unset: bool = True,
+        exclude_defaults: bool = False,
+        exclude_none: bool = False,
+        warnings: bool = True,
+    ) -> str:
+        """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation).
+
+        By default, fields that were not set by the API will not be included,
+        and keys will match the API response, *not* the property names from the model.
+
+        For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property,
+        the output will use the `"fooBar"` key (unless `use_api_names=False` is passed).
+
+        Args:
+            indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2`
+            use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`.
+            exclude_unset: Whether to exclude fields that have not been explicitly set.
+            exclude_defaults: Whether to exclude fields that have the default value.
+            exclude_none: Whether to exclude fields that have a value of `None`.
+            warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2.
+        """
+        return self.model_dump_json(
+            indent=indent,
+            by_alias=use_api_names,
+            exclude_unset=exclude_unset,
+            exclude_defaults=exclude_defaults,
+            exclude_none=exclude_none,
+            warnings=warnings,
+        )
+
+    @override
+    def __str__(self) -> str:
+        # mypy complains about an invalid self arg
+        return f"{self.__repr_name__()}({self.__repr_str__(', ')})"  # type: ignore[misc]
+
+    # Override the 'construct' method in a way that supports recursive parsing without validation.
+    # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836.
+    @classmethod
+    @override
+    def construct(  # pyright: ignore[reportIncompatibleMethodOverride]
+        __cls: Type[ModelT],
+        _fields_set: set[str] | None = None,
+        **values: object,
+    ) -> ModelT:
+        m = __cls.__new__(__cls)
+        fields_values: dict[str, object] = {}
+
+        config = get_model_config(__cls)
+        populate_by_name = (
+            config.allow_population_by_field_name
+            if isinstance(config, _ConfigProtocol)
+            else config.get("populate_by_name")
+        )
+
+        if _fields_set is None:
+            _fields_set = set()
+
+        model_fields = get_model_fields(__cls)
+        for name, field in model_fields.items():
+            key = field.alias
+            if key is None or (key not in values and populate_by_name):
+                key = name
+
+            if key in values:
+                fields_values[name] = _construct_field(value=values[key], field=field, key=key)
+                _fields_set.add(name)
+            else:
+                fields_values[name] = field_get_default(field)
+
+        _extra = {}
+        for key, value in values.items():
+            if key not in model_fields:
+                if PYDANTIC_V2:
+                    _extra[key] = value
+                else:
+                    _fields_set.add(key)
+                    fields_values[key] = value
+
+        object.__setattr__(m, "__dict__", fields_values)
+
+        if PYDANTIC_V2:
+            # these properties are copied from Pydantic's `model_construct()` method
+            object.__setattr__(m, "__pydantic_private__", None)
+            object.__setattr__(m, "__pydantic_extra__", _extra)
+            object.__setattr__(m, "__pydantic_fields_set__", _fields_set)
+        else:
+            # init_private_attributes() does not exist in v2
+            m._init_private_attributes()  # type: ignore
+
+            # copied from Pydantic v1's `construct()` method
+            object.__setattr__(m, "__fields_set__", _fields_set)
+
+        return m
+
+    if not TYPE_CHECKING:
+        # type checkers incorrectly complain about this assignment
+        # because the type signatures are technically different
+        # although not in practice
+        model_construct = construct
+
+    if not PYDANTIC_V2:
+        # we define aliases for some of the new pydantic v2 methods so
+        # that we can just document these methods without having to specify
+        # a specific pydantic version as some users may not know which
+        # pydantic version they are currently using
+
+        @override
+        def model_dump(
+            self,
+            *,
+            mode: Literal["json", "python"] | str = "python",
+            include: IncEx | None = None,
+            exclude: IncEx | None = None,
+            by_alias: bool = False,
+            exclude_unset: bool = False,
+            exclude_defaults: bool = False,
+            exclude_none: bool = False,
+            round_trip: bool = False,
+            warnings: bool | Literal["none", "warn", "error"] = True,
+            context: dict[str, Any] | None = None,
+            serialize_as_any: bool = False,
+        ) -> dict[str, Any]:
+            """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
+
+            Generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
+
+            Args:
+                mode: The mode in which `to_python` should run.
+                    If mode is 'json', the dictionary will only contain JSON serializable types.
+                    If mode is 'python', the dictionary may contain any Python objects.
+                include: A list of fields to include in the output.
+                exclude: A list of fields to exclude from the output.
+                by_alias: Whether to use the field's alias in the dictionary key if defined.
+                exclude_unset: Whether to exclude fields that are unset or None from the output.
+                exclude_defaults: Whether to exclude fields that are set to their default value from the output.
+                exclude_none: Whether to exclude fields that have a value of `None` from the output.
+                round_trip: Whether to enable serialization and deserialization round-trip support.
+                warnings: Whether to log warnings when invalid fields are encountered.
+
+            Returns:
+                A dictionary representation of the model.
+            """
+            if mode not in {"json", "python"}:
+                raise ValueError("mode must be either 'json' or 'python'")
+            if round_trip != False:
+                raise ValueError("round_trip is only supported in Pydantic v2")
+            if warnings != True:
+                raise ValueError("warnings is only supported in Pydantic v2")
+            if context is not None:
+                raise ValueError("context is only supported in Pydantic v2")
+            if serialize_as_any != False:
+                raise ValueError("serialize_as_any is only supported in Pydantic v2")
+            dumped = super().dict(  # pyright: ignore[reportDeprecated]
+                include=include,
+                exclude=exclude,
+                by_alias=by_alias,
+                exclude_unset=exclude_unset,
+                exclude_defaults=exclude_defaults,
+                exclude_none=exclude_none,
+            )
+
+            return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped
+
+        @override
+        def model_dump_json(
+            self,
+            *,
+            indent: int | None = None,
+            include: IncEx | None = None,
+            exclude: IncEx | None = None,
+            by_alias: bool = False,
+            exclude_unset: bool = False,
+            exclude_defaults: bool = False,
+            exclude_none: bool = False,
+            round_trip: bool = False,
+            warnings: bool | Literal["none", "warn", "error"] = True,
+            context: dict[str, Any] | None = None,
+            serialize_as_any: bool = False,
+        ) -> str:
+            """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json
+
+            Generates a JSON representation of the model using Pydantic's `to_json` method.
+
+            Args:
+                indent: Indentation to use in the JSON output. If None is passed, the output will be compact.
+                include: Field(s) to include in the JSON output. Can take either a string or set of strings.
+                exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings.
+                by_alias: Whether to serialize using field aliases.
+                exclude_unset: Whether to exclude fields that have not been explicitly set.
+                exclude_defaults: Whether to exclude fields that have the default value.
+                exclude_none: Whether to exclude fields that have a value of `None`.
+                round_trip: Whether to use serialization/deserialization between JSON and class instance.
+                warnings: Whether to show any warnings that occurred during serialization.
+
+            Returns:
+                A JSON string representation of the model.
+            """
+            if round_trip != False:
+                raise ValueError("round_trip is only supported in Pydantic v2")
+            if warnings != True:
+                raise ValueError("warnings is only supported in Pydantic v2")
+            if context is not None:
+                raise ValueError("context is only supported in Pydantic v2")
+            if serialize_as_any != False:
+                raise ValueError("serialize_as_any is only supported in Pydantic v2")
+            return super().json(  # type: ignore[reportDeprecated]
+                indent=indent,
+                include=include,
+                exclude=exclude,
+                by_alias=by_alias,
+                exclude_unset=exclude_unset,
+                exclude_defaults=exclude_defaults,
+                exclude_none=exclude_none,
+            )
+
+
+def _construct_field(value: object, field: FieldInfo, key: str) -> object:
+    if value is None:
+        return field_get_default(field)
+
+    if PYDANTIC_V2:
+        type_ = field.annotation
+    else:
+        type_ = cast(type, field.outer_type_)  # type: ignore
+
+    if type_ is None:
+        raise RuntimeError(f"Unexpected field type is None for {key}")
+
+    return construct_type(value=value, type_=type_)
+
+
+def is_basemodel(type_: type) -> bool:
+    """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`"""
+    if is_union(type_):
+        for variant in get_args(type_):
+            if is_basemodel(variant):
+                return True
+
+        return False
+
+    return is_basemodel_type(type_)
+
+
+def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]:
+    origin = get_origin(type_) or type_
+    if not inspect.isclass(origin):
+        return False
+    return issubclass(origin, BaseModel) or issubclass(origin, GenericModel)
+
+
+def build(
+    base_model_cls: Callable[P, _BaseModelT],
+    *args: P.args,
+    **kwargs: P.kwargs,
+) -> _BaseModelT:
+    """Construct a BaseModel class without validation.
+
+    This is useful for cases where you need to instantiate a `BaseModel`
+    from an API response as this provides type-safe params which isn't supported
+    by helpers like `construct_type()`.
+
+    ```py
+    build(MyModel, my_field_a="foo", my_field_b=123)
+    ```
+    """
+    if args:
+        raise TypeError(
+            "Received positional arguments which are not supported; Keyword arguments must be used instead",
+        )
+
+    return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs))
+
+
+def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T:
+    """Loose coercion to the expected type with construction of nested values.
+
+    Note: the returned value from this function is not guaranteed to match the
+    given type.
+    """
+    return cast(_T, construct_type(value=value, type_=type_))
+
+
+def construct_type(*, value: object, type_: object) -> object:
+    """Loose coercion to the expected type with construction of nested values.
+
+    If the given value does not match the expected type then it is returned as-is.
+    """
+
+    # store a reference to the original type we were given before we extract any inner
+    # types so that we can properly resolve forward references in `TypeAliasType` annotations
+    original_type = None
+
+    # we allow `object` as the input type because otherwise, passing things like
+    # `Literal['value']` will be reported as a type error by type checkers
+    type_ = cast("type[object]", type_)
+    if is_type_alias_type(type_):
+        original_type = type_  # type: ignore[unreachable]
+        type_ = type_.__value__  # type: ignore[unreachable]
+
+    # unwrap `Annotated[T, ...]` -> `T`
+    if is_annotated_type(type_):
+        meta: tuple[Any, ...] = get_args(type_)[1:]
+        type_ = extract_type_arg(type_, 0)
+    else:
+        meta = tuple()
+
+    # we need to use the origin class for any types that are subscripted generics
+    # e.g. Dict[str, object]
+    origin = get_origin(type_) or type_
+    args = get_args(type_)
+
+    if is_union(origin):
+        try:
+            return validate_type(type_=cast("type[object]", original_type or type_), value=value)
+        except Exception:
+            pass
+
+        # if the type is a discriminated union then we want to construct the right variant
+        # in the union, even if the data doesn't match exactly, otherwise we'd break code
+        # that relies on the constructed class types, e.g.
+        #
+        # class FooType:
+        #   kind: Literal['foo']
+        #   value: str
+        #
+        # class BarType:
+        #   kind: Literal['bar']
+        #   value: int
+        #
+        # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then
+        # we'd end up constructing `FooType` when it should be `BarType`.
+        discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta)
+        if discriminator and is_mapping(value):
+            variant_value = value.get(discriminator.field_alias_from or discriminator.field_name)
+            if variant_value and isinstance(variant_value, str):
+                variant_type = discriminator.mapping.get(variant_value)
+                if variant_type:
+                    return construct_type(type_=variant_type, value=value)
+
+        # if the data is not valid, use the first variant that doesn't fail while deserializing
+        for variant in args:
+            try:
+                return construct_type(value=value, type_=variant)
+            except Exception:
+                continue
+
+        raise RuntimeError(f"Could not convert data into a valid instance of {type_}")
+
+    if origin == dict:
+        if not is_mapping(value):
+            return value
+
+        _, items_type = get_args(type_)  # Dict[_, items_type]
+        return {key: construct_type(value=item, type_=items_type) for key, item in value.items()}
+
+    if (
+        not is_literal_type(type_)
+        and inspect.isclass(origin)
+        and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel))
+    ):
+        if is_list(value):
+            return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value]
+
+        if is_mapping(value):
+            if issubclass(type_, BaseModel):
+                return type_.construct(**value)  # type: ignore[arg-type]
+
+            return cast(Any, type_).construct(**value)
+
+    if origin == list:
+        if not is_list(value):
+            return value
+
+        inner_type = args[0]  # List[inner_type]
+        return [construct_type(value=entry, type_=inner_type) for entry in value]
+
+    if origin == float:
+        if isinstance(value, int):
+            coerced = float(value)
+            if coerced != value:
+                return value
+            return coerced
+
+        return value
+
+    if type_ == datetime:
+        try:
+            return parse_datetime(value)  # type: ignore
+        except Exception:
+            return value
+
+    if type_ == date:
+        try:
+            return parse_date(value)  # type: ignore
+        except Exception:
+            return value
+
+    return value
+
+
+@runtime_checkable
+class CachedDiscriminatorType(Protocol):
+    __discriminator__: DiscriminatorDetails
+
+
+class DiscriminatorDetails:
+    field_name: str
+    """The name of the discriminator field in the variant class, e.g.
+
+    ```py
+    class Foo(BaseModel):
+        type: Literal['foo']
+    ```
+
+    Will result in field_name='type'
+    """
+
+    field_alias_from: str | None
+    """The name of the discriminator field in the API response, e.g.
+
+    ```py
+    class Foo(BaseModel):
+        type: Literal['foo'] = Field(alias='type_from_api')
+    ```
+
+    Will result in field_alias_from='type_from_api'
+    """
+
+    mapping: dict[str, type]
+    """Mapping of discriminator value to variant type, e.g.
+
+    {'foo': FooVariant, 'bar': BarVariant}
+    """
+
+    def __init__(
+        self,
+        *,
+        mapping: dict[str, type],
+        discriminator_field: str,
+        discriminator_alias: str | None,
+    ) -> None:
+        self.mapping = mapping
+        self.field_name = discriminator_field
+        self.field_alias_from = discriminator_alias
+
+
+def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None:
+    if isinstance(union, CachedDiscriminatorType):
+        return union.__discriminator__
+
+    discriminator_field_name: str | None = None
+
+    for annotation in meta_annotations:
+        if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None:
+            discriminator_field_name = annotation.discriminator
+            break
+
+    if not discriminator_field_name:
+        return None
+
+    mapping: dict[str, type] = {}
+    discriminator_alias: str | None = None
+
+    for variant in get_args(union):
+        variant = strip_annotated_type(variant)
+        if is_basemodel_type(variant):
+            if PYDANTIC_V2:
+                field = _extract_field_schema_pv2(variant, discriminator_field_name)
+                if not field:
+                    continue
+
+                # Note: if one variant defines an alias then they all should
+                discriminator_alias = field.get("serialization_alias")
+
+                field_schema = field["schema"]
+
+                if field_schema["type"] == "literal":
+                    for entry in cast("LiteralSchema", field_schema)["expected"]:
+                        if isinstance(entry, str):
+                            mapping[entry] = variant
+            else:
+                field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name)  # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
+                if not field_info:
+                    continue
+
+                # Note: if one variant defines an alias then they all should
+                discriminator_alias = field_info.alias
+
+                if field_info.annotation and is_literal_type(field_info.annotation):
+                    for entry in get_args(field_info.annotation):
+                        if isinstance(entry, str):
+                            mapping[entry] = variant
+
+    if not mapping:
+        return None
+
+    details = DiscriminatorDetails(
+        mapping=mapping,
+        discriminator_field=discriminator_field_name,
+        discriminator_alias=discriminator_alias,
+    )
+    cast(CachedDiscriminatorType, union).__discriminator__ = details
+    return details
+
+
+def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None:
+    schema = model.__pydantic_core_schema__
+    if schema["type"] != "model":
+        return None
+
+    fields_schema = schema["schema"]
+    if fields_schema["type"] != "model-fields":
+        return None
+
+    fields_schema = cast("ModelFieldsSchema", fields_schema)
+
+    field = fields_schema["fields"].get(field_name)
+    if not field:
+        return None
+
+    return cast("ModelField", field)  # pyright: ignore[reportUnnecessaryCast]
+
+
+def validate_type(*, type_: type[_T], value: object) -> _T:
+    """Strict validation that the given value matches the expected type"""
+    if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel):
+        return cast(_T, parse_obj(type_, value))
+
+    return cast(_T, _validate_non_model_type(type_=type_, value=value))
+
+
+def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None:
+    """Add a pydantic config for the given type.
+
+    Note: this is a no-op on Pydantic v1.
+    """
+    setattr(typ, "__pydantic_config__", config)  # noqa: B010
+
+
+def add_request_id(obj: BaseModel, request_id: str | None) -> None:
+    obj._request_id = request_id
+
+    # in Pydantic v1, using setattr like we do above causes the attribute
+    # to be included when serializing the model which we don't want in this
+    # case so we need to explicitly exclude it
+    if not PYDANTIC_V2:
+        try:
+            exclude_fields = obj.__exclude_fields__  # type: ignore
+        except AttributeError:
+            cast(Any, obj).__exclude_fields__ = {"_request_id", "__exclude_fields__"}
+        else:
+            cast(Any, obj).__exclude_fields__ = {*(exclude_fields or {}), "_request_id", "__exclude_fields__"}
+
+
+# our use of subclasssing here causes weirdness for type checkers,
+# so we just pretend that we don't subclass
+if TYPE_CHECKING:
+    GenericModel = BaseModel
+else:
+
+    class GenericModel(BaseGenericModel, BaseModel):
+        pass
+
+
+if PYDANTIC_V2:
+    from pydantic import TypeAdapter as _TypeAdapter
+
+    _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter))
+
+    if TYPE_CHECKING:
+        from pydantic import TypeAdapter
+    else:
+        TypeAdapter = _CachedTypeAdapter
+
+    def _validate_non_model_type(*, type_: type[_T], value: object) -> _T:
+        return TypeAdapter(type_).validate_python(value)
+
+elif not TYPE_CHECKING:  # TODO: condition is weird
+
+    class RootModel(GenericModel, Generic[_T]):
+        """Used as a placeholder to easily convert runtime types to a Pydantic format
+        to provide validation.
+
+        For example:
+        ```py
+        validated = RootModel[int](__root__="5").__root__
+        # validated: 5
+        ```
+        """
+
+        __root__: _T
+
+    def _validate_non_model_type(*, type_: type[_T], value: object) -> _T:
+        model = _create_pydantic_model(type_).validate(value)
+        return cast(_T, model.__root__)
+
+    def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]:
+        return RootModel[type_]  # type: ignore
+
+
+class FinalRequestOptionsInput(TypedDict, total=False):
+    method: Required[str]
+    url: Required[str]
+    params: Query
+    headers: Headers
+    max_retries: int
+    timeout: float | Timeout | None
+    files: HttpxRequestFiles | None
+    idempotency_key: str
+    json_data: Body
+    extra_json: AnyMapping
+
+
+@final
+class FinalRequestOptions(pydantic.BaseModel):
+    method: str
+    url: str
+    params: Query = {}
+    headers: Union[Headers, NotGiven] = NotGiven()
+    max_retries: Union[int, NotGiven] = NotGiven()
+    timeout: Union[float, Timeout, None, NotGiven] = NotGiven()
+    files: Union[HttpxRequestFiles, None] = None
+    idempotency_key: Union[str, None] = None
+    post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
+
+    # It should be noted that we cannot use `json` here as that would override
+    # a BaseModel method in an incompatible fashion.
+    json_data: Union[Body, None] = None
+    extra_json: Union[AnyMapping, None] = None
+
+    if PYDANTIC_V2:
+        model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
+    else:
+
+        class Config(pydantic.BaseConfig):  # pyright: ignore[reportDeprecated]
+            arbitrary_types_allowed: bool = True
+
+    def get_max_retries(self, max_retries: int) -> int:
+        if isinstance(self.max_retries, NotGiven):
+            return max_retries
+        return self.max_retries
+
+    def _strip_raw_response_header(self) -> None:
+        if not is_given(self.headers):
+            return
+
+        if self.headers.get(RAW_RESPONSE_HEADER):
+            self.headers = {**self.headers}
+            self.headers.pop(RAW_RESPONSE_HEADER)
+
+    # override the `construct` method so that we can run custom transformations.
+    # this is necessary as we don't want to do any actual runtime type checking
+    # (which means we can't use validators) but we do want to ensure that `NotGiven`
+    # values are not present
+    #
+    # type ignore required because we're adding explicit types to `**values`
+    @classmethod
+    def construct(  # type: ignore
+        cls,
+        _fields_set: set[str] | None = None,
+        **values: Unpack[FinalRequestOptionsInput],
+    ) -> FinalRequestOptions:
+        kwargs: dict[str, Any] = {
+            # we unconditionally call `strip_not_given` on any value
+            # as it will just ignore any non-mapping types
+            key: strip_not_given(value)
+            for key, value in values.items()
+        }
+        if PYDANTIC_V2:
+            return super().model_construct(_fields_set, **kwargs)
+        return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs))  # pyright: ignore[reportDeprecated]
+
+    if not TYPE_CHECKING:
+        # type checkers incorrectly complain about this assignment
+        model_construct = construct
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_qs.py b/.venv/lib/python3.12/site-packages/anthropic/_qs.py
new file mode 100644
index 00000000..274320ca
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_qs.py
@@ -0,0 +1,150 @@
+from __future__ import annotations
+
+from typing import Any, List, Tuple, Union, Mapping, TypeVar
+from urllib.parse import parse_qs, urlencode
+from typing_extensions import Literal, get_args
+
+from ._types import NOT_GIVEN, NotGiven, NotGivenOr
+from ._utils import flatten
+
+_T = TypeVar("_T")
+
+
+ArrayFormat = Literal["comma", "repeat", "indices", "brackets"]
+NestedFormat = Literal["dots", "brackets"]
+
+PrimitiveData = Union[str, int, float, bool, None]
+# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"]
+# https://github.com/microsoft/pyright/issues/3555
+Data = Union[PrimitiveData, List[Any], Tuple[Any], "Mapping[str, Any]"]
+Params = Mapping[str, Data]
+
+
+class Querystring:
+    array_format: ArrayFormat
+    nested_format: NestedFormat
+
+    def __init__(
+        self,
+        *,
+        array_format: ArrayFormat = "repeat",
+        nested_format: NestedFormat = "brackets",
+    ) -> None:
+        self.array_format = array_format
+        self.nested_format = nested_format
+
+    def parse(self, query: str) -> Mapping[str, object]:
+        # Note: custom format syntax is not supported yet
+        return parse_qs(query)
+
+    def stringify(
+        self,
+        params: Params,
+        *,
+        array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN,
+        nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN,
+    ) -> str:
+        return urlencode(
+            self.stringify_items(
+                params,
+                array_format=array_format,
+                nested_format=nested_format,
+            )
+        )
+
+    def stringify_items(
+        self,
+        params: Params,
+        *,
+        array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN,
+        nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN,
+    ) -> list[tuple[str, str]]:
+        opts = Options(
+            qs=self,
+            array_format=array_format,
+            nested_format=nested_format,
+        )
+        return flatten([self._stringify_item(key, value, opts) for key, value in params.items()])
+
+    def _stringify_item(
+        self,
+        key: str,
+        value: Data,
+        opts: Options,
+    ) -> list[tuple[str, str]]:
+        if isinstance(value, Mapping):
+            items: list[tuple[str, str]] = []
+            nested_format = opts.nested_format
+            for subkey, subvalue in value.items():
+                items.extend(
+                    self._stringify_item(
+                        # TODO: error if unknown format
+                        f"{key}.{subkey}" if nested_format == "dots" else f"{key}[{subkey}]",
+                        subvalue,
+                        opts,
+                    )
+                )
+            return items
+
+        if isinstance(value, (list, tuple)):
+            array_format = opts.array_format
+            if array_format == "comma":
+                return [
+                    (
+                        key,
+                        ",".join(self._primitive_value_to_str(item) for item in value if item is not None),
+                    ),
+                ]
+            elif array_format == "repeat":
+                items = []
+                for item in value:
+                    items.extend(self._stringify_item(key, item, opts))
+                return items
+            elif array_format == "indices":
+                raise NotImplementedError("The array indices format is not supported yet")
+            elif array_format == "brackets":
+                items = []
+                key = key + "[]"
+                for item in value:
+                    items.extend(self._stringify_item(key, item, opts))
+                return items
+            else:
+                raise NotImplementedError(
+                    f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}"
+                )
+
+        serialised = self._primitive_value_to_str(value)
+        if not serialised:
+            return []
+        return [(key, serialised)]
+
+    def _primitive_value_to_str(self, value: PrimitiveData) -> str:
+        # copied from httpx
+        if value is True:
+            return "true"
+        elif value is False:
+            return "false"
+        elif value is None:
+            return ""
+        return str(value)
+
+
+_qs = Querystring()
+parse = _qs.parse
+stringify = _qs.stringify
+stringify_items = _qs.stringify_items
+
+
+class Options:
+    array_format: ArrayFormat
+    nested_format: NestedFormat
+
+    def __init__(
+        self,
+        qs: Querystring = _qs,
+        *,
+        array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN,
+        nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN,
+    ) -> None:
+        self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format
+        self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_resource.py b/.venv/lib/python3.12/site-packages/anthropic/_resource.py
new file mode 100644
index 00000000..f62cc2ba
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_resource.py
@@ -0,0 +1,41 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import time
+
+import anyio
+
+from ._base_client import SyncAPIClient, AsyncAPIClient
+
+
+class SyncAPIResource:
+    _client: SyncAPIClient
+
+    def __init__(self, client: SyncAPIClient) -> None:
+        self._client = client
+        self._get = client.get
+        self._post = client.post
+        self._patch = client.patch
+        self._put = client.put
+        self._delete = client.delete
+        self._get_api_list = client.get_api_list
+
+    def _sleep(self, seconds: float) -> None:
+        time.sleep(seconds)
+
+
+class AsyncAPIResource:
+    _client: AsyncAPIClient
+
+    def __init__(self, client: AsyncAPIClient) -> None:
+        self._client = client
+        self._get = client.get
+        self._post = client.post
+        self._patch = client.patch
+        self._put = client.put
+        self._delete = client.delete
+        self._get_api_list = client.get_api_list
+
+    async def _sleep(self, seconds: float) -> None:
+        await anyio.sleep(seconds)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_response.py b/.venv/lib/python3.12/site-packages/anthropic/_response.py
new file mode 100644
index 00000000..64a3f158
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_response.py
@@ -0,0 +1,872 @@
+from __future__ import annotations
+
+import os
+import inspect
+import logging
+import datetime
+import functools
+from types import TracebackType
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    Union,
+    Generic,
+    TypeVar,
+    Callable,
+    Iterator,
+    AsyncIterator,
+    cast,
+    overload,
+)
+from typing_extensions import Awaitable, ParamSpec, override, get_origin
+
+import anyio
+import httpx
+import pydantic
+
+from ._types import NoneType
+from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base
+from ._models import BaseModel, is_basemodel, add_request_id
+from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER
+from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type
+from ._exceptions import AnthropicError, APIResponseValidationError
+from ._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder
+
+if TYPE_CHECKING:
+    from ._models import FinalRequestOptions
+    from ._base_client import BaseClient
+
+
+P = ParamSpec("P")
+R = TypeVar("R")
+_T = TypeVar("_T")
+_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]")
+_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]")
+
+log: logging.Logger = logging.getLogger(__name__)
+
+
+class BaseAPIResponse(Generic[R]):
+    _cast_to: type[R]
+    _client: BaseClient[Any, Any]
+    _parsed_by_type: dict[type[Any], Any]
+    _is_sse_stream: bool
+    _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None
+    _options: FinalRequestOptions
+
+    http_response: httpx.Response
+
+    retries_taken: int
+    """The number of retries made. If no retries happened this will be `0`"""
+
+    def __init__(
+        self,
+        *,
+        raw: httpx.Response,
+        cast_to: type[R],
+        client: BaseClient[Any, Any],
+        stream: bool,
+        stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
+        options: FinalRequestOptions,
+        retries_taken: int = 0,
+    ) -> None:
+        self._cast_to = cast_to
+        self._client = client
+        self._parsed_by_type = {}
+        self._is_sse_stream = stream
+        self._stream_cls = stream_cls
+        self._options = options
+        self.http_response = raw
+        self.retries_taken = retries_taken
+
+    @property
+    def headers(self) -> httpx.Headers:
+        return self.http_response.headers
+
+    @property
+    def http_request(self) -> httpx.Request:
+        """Returns the httpx Request instance associated with the current response."""
+        return self.http_response.request
+
+    @property
+    def status_code(self) -> int:
+        return self.http_response.status_code
+
+    @property
+    def url(self) -> httpx.URL:
+        """Returns the URL for which the request was made."""
+        return self.http_response.url
+
+    @property
+    def method(self) -> str:
+        return self.http_request.method
+
+    @property
+    def http_version(self) -> str:
+        return self.http_response.http_version
+
+    @property
+    def elapsed(self) -> datetime.timedelta:
+        """The time taken for the complete request/response cycle to complete."""
+        return self.http_response.elapsed
+
+    @property
+    def is_closed(self) -> bool:
+        """Whether or not the response body has been closed.
+
+        If this is False then there is response data that has not been read yet.
+        You must either fully consume the response body or call `.close()`
+        before discarding the response to prevent resource leaks.
+        """
+        return self.http_response.is_closed
+
+    @override
+    def __repr__(self) -> str:
+        return (
+            f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>"
+        )
+
+    def _parse(self, *, to: type[_T] | None = None) -> R | _T:
+        cast_to = to if to is not None else self._cast_to
+
+        # unwrap `TypeAlias('Name', T)` -> `T`
+        if is_type_alias_type(cast_to):
+            cast_to = cast_to.__value__  # type: ignore[unreachable]
+
+        # unwrap `Annotated[T, ...]` -> `T`
+        if cast_to and is_annotated_type(cast_to):
+            cast_to = extract_type_arg(cast_to, 0)
+
+        origin = get_origin(cast_to) or cast_to
+
+        if inspect.isclass(origin):
+            if issubclass(cast(Any, origin), JSONLDecoder):
+                return cast(
+                    R,
+                    cast("type[JSONLDecoder[Any]]", cast_to)(
+                        raw_iterator=self.http_response.iter_bytes(chunk_size=64),
+                        line_type=extract_type_arg(cast_to, 0),
+                        http_response=self.http_response,
+                    ),
+                )
+
+            if issubclass(cast(Any, origin), AsyncJSONLDecoder):
+                return cast(
+                    R,
+                    cast("type[AsyncJSONLDecoder[Any]]", cast_to)(
+                        raw_iterator=self.http_response.aiter_bytes(chunk_size=64),
+                        line_type=extract_type_arg(cast_to, 0),
+                        http_response=self.http_response,
+                    ),
+                )
+
+        if self._is_sse_stream:
+            if to:
+                if not is_stream_class_type(to):
+                    raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}")
+
+                return cast(
+                    _T,
+                    to(
+                        cast_to=extract_stream_chunk_type(
+                            to,
+                            failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]",
+                        ),
+                        response=self.http_response,
+                        client=cast(Any, self._client),
+                    ),
+                )
+
+            if self._stream_cls:
+                return cast(
+                    R,
+                    self._stream_cls(
+                        cast_to=extract_stream_chunk_type(self._stream_cls),
+                        response=self.http_response,
+                        client=cast(Any, self._client),
+                    ),
+                )
+
+            stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls)
+            if stream_cls is None:
+                raise MissingStreamClassError()
+
+            return cast(
+                R,
+                stream_cls(
+                    cast_to=cast_to,
+                    response=self.http_response,
+                    client=cast(Any, self._client),
+                ),
+            )
+
+        if cast_to is NoneType:
+            return cast(R, None)
+
+        response = self.http_response
+        if cast_to == str:
+            return cast(R, response.text)
+
+        if cast_to == bytes:
+            return cast(R, response.content)
+
+        if cast_to == int:
+            return cast(R, int(response.text))
+
+        if cast_to == float:
+            return cast(R, float(response.text))
+
+        if cast_to == bool:
+            return cast(R, response.text.lower() == "true")
+
+        # handle the legacy binary response case
+        if inspect.isclass(cast_to) and cast_to.__name__ == "HttpxBinaryResponseContent":
+            return cast(R, cast_to(response))  # type: ignore
+
+        if origin == APIResponse:
+            raise RuntimeError("Unexpected state - cast_to is `APIResponse`")
+
+        if inspect.isclass(
+            origin  # pyright: ignore[reportUnknownArgumentType]
+        ) and issubclass(origin, httpx.Response):
+            # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response
+            # and pass that class to our request functions. We cannot change the variance to be either
+            # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct
+            # the response class ourselves but that is something that should be supported directly in httpx
+            # as it would be easy to incorrectly construct the Response object due to the multitude of arguments.
+            if cast_to != httpx.Response:
+                raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`")
+            return cast(R, response)
+
+        if (
+            inspect.isclass(
+                origin  # pyright: ignore[reportUnknownArgumentType]
+            )
+            and not issubclass(origin, BaseModel)
+            and issubclass(origin, pydantic.BaseModel)
+        ):
+            raise TypeError("Pydantic models must subclass our base model type, e.g. `from anthropic import BaseModel`")
+
+        if (
+            cast_to is not object
+            and not origin is list
+            and not origin is dict
+            and not origin is Union
+            and not issubclass(origin, BaseModel)
+        ):
+            raise RuntimeError(
+                f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}."
+            )
+
+        # split is required to handle cases where additional information is included
+        # in the response, e.g. application/json; charset=utf-8
+        content_type, *_ = response.headers.get("content-type", "*").split(";")
+        if content_type != "application/json":
+            if is_basemodel(cast_to):
+                try:
+                    data = response.json()
+                except Exception as exc:
+                    log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc)
+                else:
+                    return self._client._process_response_data(
+                        data=data,
+                        cast_to=cast_to,  # type: ignore
+                        response=response,
+                    )
+
+            if self._client._strict_response_validation:
+                raise APIResponseValidationError(
+                    response=response,
+                    message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.",
+                    body=response.text,
+                )
+
+            # If the API responds with content that isn't JSON then we just return
+            # the (decoded) text without performing any parsing so that you can still
+            # handle the response however you need to.
+            return response.text  # type: ignore
+
+        data = response.json()
+
+        return self._client._process_response_data(
+            data=data,
+            cast_to=cast_to,  # type: ignore
+            response=response,
+        )
+
+
+class APIResponse(BaseAPIResponse[R]):
+    @property
+    def request_id(self) -> str | None:
+        return self.http_response.headers.get("request-id")  # type: ignore[no-any-return]
+
+    @overload
+    def parse(self, *, to: type[_T]) -> _T: ...
+
+    @overload
+    def parse(self) -> R: ...
+
+    def parse(self, *, to: type[_T] | None = None) -> R | _T:
+        """Returns the rich python representation of this response's data.
+
+        For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`.
+
+        You can customise the type that the response is parsed into through
+        the `to` argument, e.g.
+
+        ```py
+        from anthropic import BaseModel
+
+
+        class MyModel(BaseModel):
+            foo: str
+
+
+        obj = response.parse(to=MyModel)
+        print(obj.foo)
+        ```
+
+        We support parsing:
+          - `BaseModel`
+          - `dict`
+          - `list`
+          - `Union`
+          - `str`
+          - `int`
+          - `float`
+          - `httpx.Response`
+        """
+        cache_key = to if to is not None else self._cast_to
+        cached = self._parsed_by_type.get(cache_key)
+        if cached is not None:
+            return cached  # type: ignore[no-any-return]
+
+        if not self._is_sse_stream:
+            self.read()
+
+        parsed = self._parse(to=to)
+        if is_given(self._options.post_parser):
+            parsed = self._options.post_parser(parsed)
+
+        if isinstance(parsed, BaseModel):
+            add_request_id(parsed, self.request_id)
+
+        self._parsed_by_type[cache_key] = parsed
+        return cast(R, parsed)
+
+    def read(self) -> bytes:
+        """Read and return the binary response content."""
+        try:
+            return self.http_response.read()
+        except httpx.StreamConsumed as exc:
+            # The default error raised by httpx isn't very
+            # helpful in our case so we re-raise it with
+            # a different error message.
+            raise StreamAlreadyConsumed() from exc
+
+    def text(self) -> str:
+        """Read and decode the response content into a string."""
+        self.read()
+        return self.http_response.text
+
+    def json(self) -> object:
+        """Read and decode the JSON response content."""
+        self.read()
+        return self.http_response.json()
+
+    def close(self) -> None:
+        """Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        self.http_response.close()
+
+    def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]:
+        """
+        A byte-iterator over the decoded response content.
+
+        This automatically handles gzip, deflate and brotli encoded responses.
+        """
+        for chunk in self.http_response.iter_bytes(chunk_size):
+            yield chunk
+
+    def iter_text(self, chunk_size: int | None = None) -> Iterator[str]:
+        """A str-iterator over the decoded response content
+        that handles both gzip, deflate, etc but also detects the content's
+        string encoding.
+        """
+        for chunk in self.http_response.iter_text(chunk_size):
+            yield chunk
+
+    def iter_lines(self) -> Iterator[str]:
+        """Like `iter_text()` but will only yield chunks for each line"""
+        for chunk in self.http_response.iter_lines():
+            yield chunk
+
+
+class AsyncAPIResponse(BaseAPIResponse[R]):
+    @property
+    def request_id(self) -> str | None:
+        return self.http_response.headers.get("request-id")  # type: ignore[no-any-return]
+
+    @overload
+    async def parse(self, *, to: type[_T]) -> _T: ...
+
+    @overload
+    async def parse(self) -> R: ...
+
+    async def parse(self, *, to: type[_T] | None = None) -> R | _T:
+        """Returns the rich python representation of this response's data.
+
+        For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`.
+
+        You can customise the type that the response is parsed into through
+        the `to` argument, e.g.
+
+        ```py
+        from anthropic import BaseModel
+
+
+        class MyModel(BaseModel):
+            foo: str
+
+
+        obj = response.parse(to=MyModel)
+        print(obj.foo)
+        ```
+
+        We support parsing:
+          - `BaseModel`
+          - `dict`
+          - `list`
+          - `Union`
+          - `str`
+          - `httpx.Response`
+        """
+        cache_key = to if to is not None else self._cast_to
+        cached = self._parsed_by_type.get(cache_key)
+        if cached is not None:
+            return cached  # type: ignore[no-any-return]
+
+        if not self._is_sse_stream:
+            await self.read()
+
+        parsed = self._parse(to=to)
+        if is_given(self._options.post_parser):
+            parsed = self._options.post_parser(parsed)
+
+        if isinstance(parsed, BaseModel):
+            add_request_id(parsed, self.request_id)
+
+        self._parsed_by_type[cache_key] = parsed
+        return cast(R, parsed)
+
+    async def read(self) -> bytes:
+        """Read and return the binary response content."""
+        try:
+            return await self.http_response.aread()
+        except httpx.StreamConsumed as exc:
+            # the default error raised by httpx isn't very
+            # helpful in our case so we re-raise it with
+            # a different error message
+            raise StreamAlreadyConsumed() from exc
+
+    async def text(self) -> str:
+        """Read and decode the response content into a string."""
+        await self.read()
+        return self.http_response.text
+
+    async def json(self) -> object:
+        """Read and decode the JSON response content."""
+        await self.read()
+        return self.http_response.json()
+
+    async def close(self) -> None:
+        """Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        await self.http_response.aclose()
+
+    async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]:
+        """
+        A byte-iterator over the decoded response content.
+
+        This automatically handles gzip, deflate and brotli encoded responses.
+        """
+        async for chunk in self.http_response.aiter_bytes(chunk_size):
+            yield chunk
+
+    async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]:
+        """A str-iterator over the decoded response content
+        that handles both gzip, deflate, etc but also detects the content's
+        string encoding.
+        """
+        async for chunk in self.http_response.aiter_text(chunk_size):
+            yield chunk
+
+    async def iter_lines(self) -> AsyncIterator[str]:
+        """Like `iter_text()` but will only yield chunks for each line"""
+        async for chunk in self.http_response.aiter_lines():
+            yield chunk
+
+
+class BinaryAPIResponse(APIResponse[bytes]):
+    """Subclass of APIResponse providing helpers for dealing with binary data.
+
+    Note: If you want to stream the response data instead of eagerly reading it
+    all at once then you should use `.with_streaming_response` when making
+    the API request, e.g. `.with_streaming_response.get_binary_response()`
+    """
+
+    def write_to_file(
+        self,
+        file: str | os.PathLike[str],
+    ) -> None:
+        """Write the output to the given file.
+
+        Accepts a filename or any path-like object, e.g. pathlib.Path
+
+        Note: if you want to stream the data to the file instead of writing
+        all at once then you should use `.with_streaming_response` when making
+        the API request, e.g. `.with_streaming_response.get_binary_response()`
+        """
+        with open(file, mode="wb") as f:
+            for data in self.iter_bytes():
+                f.write(data)
+
+
+class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]):
+    """Subclass of APIResponse providing helpers for dealing with binary data.
+
+    Note: If you want to stream the response data instead of eagerly reading it
+    all at once then you should use `.with_streaming_response` when making
+    the API request, e.g. `.with_streaming_response.get_binary_response()`
+    """
+
+    async def write_to_file(
+        self,
+        file: str | os.PathLike[str],
+    ) -> None:
+        """Write the output to the given file.
+
+        Accepts a filename or any path-like object, e.g. pathlib.Path
+
+        Note: if you want to stream the data to the file instead of writing
+        all at once then you should use `.with_streaming_response` when making
+        the API request, e.g. `.with_streaming_response.get_binary_response()`
+        """
+        path = anyio.Path(file)
+        async with await path.open(mode="wb") as f:
+            async for data in self.iter_bytes():
+                await f.write(data)
+
+
+class StreamedBinaryAPIResponse(APIResponse[bytes]):
+    def stream_to_file(
+        self,
+        file: str | os.PathLike[str],
+        *,
+        chunk_size: int | None = None,
+    ) -> None:
+        """Streams the output to the given file.
+
+        Accepts a filename or any path-like object, e.g. pathlib.Path
+        """
+        with open(file, mode="wb") as f:
+            for data in self.iter_bytes(chunk_size):
+                f.write(data)
+
+
+class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]):
+    async def stream_to_file(
+        self,
+        file: str | os.PathLike[str],
+        *,
+        chunk_size: int | None = None,
+    ) -> None:
+        """Streams the output to the given file.
+
+        Accepts a filename or any path-like object, e.g. pathlib.Path
+        """
+        path = anyio.Path(file)
+        async with await path.open(mode="wb") as f:
+            async for data in self.iter_bytes(chunk_size):
+                await f.write(data)
+
+
+class MissingStreamClassError(TypeError):
+    def __init__(self) -> None:
+        super().__init__(
+            "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `anthropic._streaming` for reference",
+        )
+
+
+class StreamAlreadyConsumed(AnthropicError):
+    """
+    Attempted to read or stream content, but the content has already
+    been streamed.
+
+    This can happen if you use a method like `.iter_lines()` and then attempt
+    to read th entire response body afterwards, e.g.
+
+    ```py
+    response = await client.post(...)
+    async for line in response.iter_lines():
+        ...  # do something with `line`
+
+    content = await response.read()
+    # ^ error
+    ```
+
+    If you want this behaviour you'll need to either manually accumulate the response
+    content or call `await response.read()` before iterating over the stream.
+    """
+
+    def __init__(self) -> None:
+        message = (
+            "Attempted to read or stream some content, but the content has "
+            "already been streamed. "
+            "This could be due to attempting to stream the response "
+            "content more than once."
+            "\n\n"
+            "You can fix this by manually accumulating the response content while streaming "
+            "or by calling `.read()` before starting to stream."
+        )
+        super().__init__(message)
+
+
+class ResponseContextManager(Generic[_APIResponseT]):
+    """Context manager for ensuring that a request is not made
+    until it is entered and that the response will always be closed
+    when the context manager exits
+    """
+
+    def __init__(self, request_func: Callable[[], _APIResponseT]) -> None:
+        self._request_func = request_func
+        self.__response: _APIResponseT | None = None
+
+    def __enter__(self) -> _APIResponseT:
+        self.__response = self._request_func()
+        return self.__response
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        if self.__response is not None:
+            self.__response.close()
+
+
+class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]):
+    """Context manager for ensuring that a request is not made
+    until it is entered and that the response will always be closed
+    when the context manager exits
+    """
+
+    def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None:
+        self._api_request = api_request
+        self.__response: _AsyncAPIResponseT | None = None
+
+    async def __aenter__(self) -> _AsyncAPIResponseT:
+        self.__response = await self._api_request
+        return self.__response
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        if self.__response is not None:
+            await self.__response.close()
+
+
+def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]:
+    """Higher order function that takes one of our bound API methods and wraps it
+    to support streaming and returning the raw `APIResponse` object directly.
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]:
+        extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "stream"
+
+        kwargs["extra_headers"] = extra_headers
+
+        make_request = functools.partial(func, *args, **kwargs)
+
+        return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request))
+
+    return wrapped
+
+
+def async_to_streamed_response_wrapper(
+    func: Callable[P, Awaitable[R]],
+) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]:
+    """Higher order function that takes one of our bound API methods and wraps it
+    to support streaming and returning the raw `APIResponse` object directly.
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]:
+        extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "stream"
+
+        kwargs["extra_headers"] = extra_headers
+
+        make_request = func(*args, **kwargs)
+
+        return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request))
+
+    return wrapped
+
+
+def to_custom_streamed_response_wrapper(
+    func: Callable[P, object],
+    response_cls: type[_APIResponseT],
+) -> Callable[P, ResponseContextManager[_APIResponseT]]:
+    """Higher order function that takes one of our bound API methods and an `APIResponse` class
+    and wraps the method to support streaming and returning the given response class directly.
+
+    Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])`
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]:
+        extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "stream"
+        extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls
+
+        kwargs["extra_headers"] = extra_headers
+
+        make_request = functools.partial(func, *args, **kwargs)
+
+        return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request))
+
+    return wrapped
+
+
+def async_to_custom_streamed_response_wrapper(
+    func: Callable[P, Awaitable[object]],
+    response_cls: type[_AsyncAPIResponseT],
+) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]:
+    """Higher order function that takes one of our bound API methods and an `APIResponse` class
+    and wraps the method to support streaming and returning the given response class directly.
+
+    Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])`
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]:
+        extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "stream"
+        extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls
+
+        kwargs["extra_headers"] = extra_headers
+
+        make_request = func(*args, **kwargs)
+
+        return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request))
+
+    return wrapped
+
+
+def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]:
+    """Higher order function that takes one of our bound API methods and wraps it
+    to support returning the raw `APIResponse` object directly.
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]:
+        extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "raw"
+
+        kwargs["extra_headers"] = extra_headers
+
+        return cast(APIResponse[R], func(*args, **kwargs))
+
+    return wrapped
+
+
+def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]:
+    """Higher order function that takes one of our bound API methods and wraps it
+    to support returning the raw `APIResponse` object directly.
+    """
+
+    @functools.wraps(func)
+    async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]:
+        extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "raw"
+
+        kwargs["extra_headers"] = extra_headers
+
+        return cast(AsyncAPIResponse[R], await func(*args, **kwargs))
+
+    return wrapped
+
+
+def to_custom_raw_response_wrapper(
+    func: Callable[P, object],
+    response_cls: type[_APIResponseT],
+) -> Callable[P, _APIResponseT]:
+    """Higher order function that takes one of our bound API methods and an `APIResponse` class
+    and wraps the method to support returning the given response class directly.
+
+    Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])`
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT:
+        extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "raw"
+        extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls
+
+        kwargs["extra_headers"] = extra_headers
+
+        return cast(_APIResponseT, func(*args, **kwargs))
+
+    return wrapped
+
+
+def async_to_custom_raw_response_wrapper(
+    func: Callable[P, Awaitable[object]],
+    response_cls: type[_AsyncAPIResponseT],
+) -> Callable[P, Awaitable[_AsyncAPIResponseT]]:
+    """Higher order function that takes one of our bound API methods and an `APIResponse` class
+    and wraps the method to support returning the given response class directly.
+
+    Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])`
+    """
+
+    @functools.wraps(func)
+    def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]:
+        extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})}
+        extra_headers[RAW_RESPONSE_HEADER] = "raw"
+        extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls
+
+        kwargs["extra_headers"] = extra_headers
+
+        return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs))
+
+    return wrapped
+
+
+def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type:
+    """Given a type like `APIResponse[T]`, returns the generic type variable `T`.
+
+    This also handles the case where a concrete subclass is given, e.g.
+    ```py
+    class MyResponse(APIResponse[bytes]):
+        ...
+
+    extract_response_type(MyResponse) -> bytes
+    ```
+    """
+    return extract_type_var_from_base(
+        typ,
+        generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)),
+        index=0,
+    )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_streaming.py b/.venv/lib/python3.12/site-packages/anthropic/_streaming.py
new file mode 100644
index 00000000..d43e2e6a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_streaming.py
@@ -0,0 +1,443 @@
+# Note: initially copied from https://github.com/florimondmanca/httpx-sse/blob/master/src/httpx_sse/_decoders.py
+from __future__ import annotations
+
+import abc
+import json
+import inspect
+import warnings
+from types import TracebackType
+from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast
+from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable
+
+import httpx
+
+from ._utils import is_dict, extract_type_var_from_base
+
+if TYPE_CHECKING:
+    from ._client import Anthropic, AsyncAnthropic
+
+
+_T = TypeVar("_T")
+
+
+class _SyncStreamMeta(abc.ABCMeta):
+    @override
+    def __instancecheck__(self, instance: Any) -> bool:
+        # we override the `isinstance()` check for `Stream`
+        # as a previous version of the `MessageStream` class
+        # inherited from `Stream` & without this workaround,
+        # changing it to not inherit would be a breaking change.
+
+        from .lib.streaming import MessageStream
+
+        if isinstance(instance, MessageStream):
+            warnings.warn(
+                "Using `isinstance()` to check if a `MessageStream` object is an instance of `Stream` is deprecated & will be removed in the next major version",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+            return True
+
+        return False
+
+
+class Stream(Generic[_T], metaclass=_SyncStreamMeta):
+    """Provides the core interface to iterate over a synchronous stream response."""
+
+    response: httpx.Response
+
+    _decoder: SSEBytesDecoder
+
+    def __init__(
+        self,
+        *,
+        cast_to: type[_T],
+        response: httpx.Response,
+        client: Anthropic,
+    ) -> None:
+        self.response = response
+        self._cast_to = cast_to
+        self._client = client
+        self._decoder = client._make_sse_decoder()
+        self._iterator = self.__stream__()
+
+    def __next__(self) -> _T:
+        return self._iterator.__next__()
+
+    def __iter__(self) -> Iterator[_T]:
+        for item in self._iterator:
+            yield item
+
+    def _iter_events(self) -> Iterator[ServerSentEvent]:
+        yield from self._decoder.iter_bytes(self.response.iter_bytes())
+
+    def __stream__(self) -> Iterator[_T]:
+        cast_to = cast(Any, self._cast_to)
+        response = self.response
+        process_data = self._client._process_response_data
+        iterator = self._iter_events()
+
+        for sse in iterator:
+            if sse.event == "completion":
+                yield process_data(data=sse.json(), cast_to=cast_to, response=response)
+
+            if (
+                sse.event == "message_start"
+                or sse.event == "message_delta"
+                or sse.event == "message_stop"
+                or sse.event == "content_block_start"
+                or sse.event == "content_block_delta"
+                or sse.event == "content_block_stop"
+            ):
+                data = sse.json()
+                if is_dict(data) and "type" not in data:
+                    data["type"] = sse.event
+
+                yield process_data(data=data, cast_to=cast_to, response=response)
+
+            if sse.event == "ping":
+                continue
+
+            if sse.event == "error":
+                body = sse.data
+
+                try:
+                    body = sse.json()
+                    err_msg = f"{body}"
+                except Exception:
+                    err_msg = sse.data or f"Error code: {response.status_code}"
+
+                raise self._client._make_status_error(
+                    err_msg,
+                    body=body,
+                    response=self.response,
+                )
+
+        # Ensure the entire stream is consumed
+        for _sse in iterator:
+            ...
+
+    def __enter__(self) -> Self:
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.close()
+
+    def close(self) -> None:
+        """
+        Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        self.response.close()
+
+
+class _AsyncStreamMeta(abc.ABCMeta):
+    @override
+    def __instancecheck__(self, instance: Any) -> bool:
+        # we override the `isinstance()` check for `AsyncStream`
+        # as a previous version of the `AsyncMessageStream` class
+        # inherited from `AsyncStream` & without this workaround,
+        # changing it to not inherit would be a breaking change.
+
+        from .lib.streaming import AsyncMessageStream
+
+        if isinstance(instance, AsyncMessageStream):
+            warnings.warn(
+                "Using `isinstance()` to check if a `AsyncMessageStream` object is an instance of `AsyncStream` is deprecated & will be removed in the next major version",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+            return True
+
+        return False
+
+
+class AsyncStream(Generic[_T], metaclass=_AsyncStreamMeta):
+    """Provides the core interface to iterate over an asynchronous stream response."""
+
+    response: httpx.Response
+
+    _decoder: SSEDecoder | SSEBytesDecoder
+
+    def __init__(
+        self,
+        *,
+        cast_to: type[_T],
+        response: httpx.Response,
+        client: AsyncAnthropic,
+    ) -> None:
+        self.response = response
+        self._cast_to = cast_to
+        self._client = client
+        self._decoder = client._make_sse_decoder()
+        self._iterator = self.__stream__()
+
+    async def __anext__(self) -> _T:
+        return await self._iterator.__anext__()
+
+    async def __aiter__(self) -> AsyncIterator[_T]:
+        async for item in self._iterator:
+            yield item
+
+    async def _iter_events(self) -> AsyncIterator[ServerSentEvent]:
+        async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()):
+            yield sse
+
+    async def __stream__(self) -> AsyncIterator[_T]:
+        cast_to = cast(Any, self._cast_to)
+        response = self.response
+        process_data = self._client._process_response_data
+        iterator = self._iter_events()
+
+        async for sse in iterator:
+            if sse.event == "completion":
+                yield process_data(data=sse.json(), cast_to=cast_to, response=response)
+
+            if (
+                sse.event == "message_start"
+                or sse.event == "message_delta"
+                or sse.event == "message_stop"
+                or sse.event == "content_block_start"
+                or sse.event == "content_block_delta"
+                or sse.event == "content_block_stop"
+            ):
+                data = sse.json()
+                if is_dict(data) and "type" not in data:
+                    data["type"] = sse.event
+
+                yield process_data(data=data, cast_to=cast_to, response=response)
+
+            if sse.event == "ping":
+                continue
+
+            if sse.event == "error":
+                body = sse.data
+
+                try:
+                    body = sse.json()
+                    err_msg = f"{body}"
+                except Exception:
+                    err_msg = sse.data or f"Error code: {response.status_code}"
+
+                raise self._client._make_status_error(
+                    err_msg,
+                    body=body,
+                    response=self.response,
+                )
+
+        # Ensure the entire stream is consumed
+        async for _sse in iterator:
+            ...
+
+    async def __aenter__(self) -> Self:
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        await self.close()
+
+    async def close(self) -> None:
+        """
+        Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        await self.response.aclose()
+
+
+class ServerSentEvent:
+    def __init__(
+        self,
+        *,
+        event: str | None = None,
+        data: str | None = None,
+        id: str | None = None,
+        retry: int | None = None,
+    ) -> None:
+        if data is None:
+            data = ""
+
+        self._id = id
+        self._data = data
+        self._event = event or None
+        self._retry = retry
+
+    @property
+    def event(self) -> str | None:
+        return self._event
+
+    @property
+    def id(self) -> str | None:
+        return self._id
+
+    @property
+    def retry(self) -> int | None:
+        return self._retry
+
+    @property
+    def data(self) -> str:
+        return self._data
+
+    def json(self) -> Any:
+        return json.loads(self.data)
+
+    @override
+    def __repr__(self) -> str:
+        return f"ServerSentEvent(event={self.event}, data={self.data}, id={self.id}, retry={self.retry})"
+
+
+class SSEDecoder:
+    _data: list[str]
+    _event: str | None
+    _retry: int | None
+    _last_event_id: str | None
+
+    def __init__(self) -> None:
+        self._event = None
+        self._data = []
+        self._last_event_id = None
+        self._retry = None
+
+    def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]:
+        """Given an iterator that yields raw binary data, iterate over it & yield every event encountered"""
+        for chunk in self._iter_chunks(iterator):
+            # Split before decoding so splitlines() only uses \r and \n
+            for raw_line in chunk.splitlines():
+                line = raw_line.decode("utf-8")
+                sse = self.decode(line)
+                if sse:
+                    yield sse
+
+    def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]:
+        """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks"""
+        data = b""
+        for chunk in iterator:
+            for line in chunk.splitlines(keepends=True):
+                data += line
+                if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")):
+                    yield data
+                    data = b""
+        if data:
+            yield data
+
+    async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]:
+        """Given an iterator that yields raw binary data, iterate over it & yield every event encountered"""
+        async for chunk in self._aiter_chunks(iterator):
+            # Split before decoding so splitlines() only uses \r and \n
+            for raw_line in chunk.splitlines():
+                line = raw_line.decode("utf-8")
+                sse = self.decode(line)
+                if sse:
+                    yield sse
+
+    async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]:
+        """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks"""
+        data = b""
+        async for chunk in iterator:
+            for line in chunk.splitlines(keepends=True):
+                data += line
+                if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")):
+                    yield data
+                    data = b""
+        if data:
+            yield data
+
+    def decode(self, line: str) -> ServerSentEvent | None:
+        # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation  # noqa: E501
+
+        if not line:
+            if not self._event and not self._data and not self._last_event_id and self._retry is None:
+                return None
+
+            sse = ServerSentEvent(
+                event=self._event,
+                data="\n".join(self._data),
+                id=self._last_event_id,
+                retry=self._retry,
+            )
+
+            # NOTE: as per the SSE spec, do not reset last_event_id.
+            self._event = None
+            self._data = []
+            self._retry = None
+
+            return sse
+
+        if line.startswith(":"):
+            return None
+
+        fieldname, _, value = line.partition(":")
+
+        if value.startswith(" "):
+            value = value[1:]
+
+        if fieldname == "event":
+            self._event = value
+        elif fieldname == "data":
+            self._data.append(value)
+        elif fieldname == "id":
+            if "\0" in value:
+                pass
+            else:
+                self._last_event_id = value
+        elif fieldname == "retry":
+            try:
+                self._retry = int(value)
+            except (TypeError, ValueError):
+                pass
+        else:
+            pass  # Field is ignored.
+
+        return None
+
+
+@runtime_checkable
+class SSEBytesDecoder(Protocol):
+    def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]:
+        """Given an iterator that yields raw binary data, iterate over it & yield every event encountered"""
+        ...
+
+    def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]:
+        """Given an async iterator that yields raw binary data, iterate over it & yield every event encountered"""
+        ...
+
+
+def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]:
+    """TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`"""
+    origin = get_origin(typ) or typ
+    return inspect.isclass(origin) and issubclass(origin, (Stream, AsyncStream))
+
+
+def extract_stream_chunk_type(
+    stream_cls: type,
+    *,
+    failure_message: str | None = None,
+) -> type:
+    """Given a type like `Stream[T]`, returns the generic type variable `T`.
+
+    This also handles the case where a concrete subclass is given, e.g.
+    ```py
+    class MyStream(Stream[bytes]):
+        ...
+
+    extract_stream_chunk_type(MyStream) -> bytes
+    ```
+    """
+    from ._base_client import Stream, AsyncStream
+
+    return extract_type_var_from_base(
+        stream_cls,
+        index=0,
+        generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)),
+        failure_message=failure_message,
+    )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_types.py b/.venv/lib/python3.12/site-packages/anthropic/_types.py
new file mode 100644
index 00000000..d80c2081
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_types.py
@@ -0,0 +1,219 @@
+from __future__ import annotations
+
+from os import PathLike
+from typing import (
+    IO,
+    TYPE_CHECKING,
+    Any,
+    Dict,
+    List,
+    Type,
+    Tuple,
+    Union,
+    Mapping,
+    TypeVar,
+    Callable,
+    Optional,
+    Sequence,
+)
+from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable
+
+import httpx
+import pydantic
+from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport
+
+if TYPE_CHECKING:
+    from ._models import BaseModel
+    from ._response import APIResponse, AsyncAPIResponse
+    from ._legacy_response import HttpxBinaryResponseContent
+
+Transport = BaseTransport
+AsyncTransport = AsyncBaseTransport
+Query = Mapping[str, object]
+Body = object
+AnyMapping = Mapping[str, object]
+ModelT = TypeVar("ModelT", bound=pydantic.BaseModel)
+_T = TypeVar("_T")
+
+
+# Approximates httpx internal ProxiesTypes and RequestFiles types
+# while adding support for `PathLike` instances
+ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]]
+ProxiesTypes = Union[str, Proxy, ProxiesDict]
+if TYPE_CHECKING:
+    Base64FileInput = Union[IO[bytes], PathLike[str]]
+    FileContent = Union[IO[bytes], bytes, PathLike[str]]
+else:
+    Base64FileInput = Union[IO[bytes], PathLike]
+    FileContent = Union[IO[bytes], bytes, PathLike]  # PathLike is not subscriptable in Python 3.8.
+FileTypes = Union[
+    # file (or bytes)
+    FileContent,
+    # (filename, file (or bytes))
+    Tuple[Optional[str], FileContent],
+    # (filename, file (or bytes), content_type)
+    Tuple[Optional[str], FileContent, Optional[str]],
+    # (filename, file (or bytes), content_type, headers)
+    Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]],
+]
+RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]]
+
+# duplicate of the above but without our custom file support
+HttpxFileContent = Union[IO[bytes], bytes]
+HttpxFileTypes = Union[
+    # file (or bytes)
+    HttpxFileContent,
+    # (filename, file (or bytes))
+    Tuple[Optional[str], HttpxFileContent],
+    # (filename, file (or bytes), content_type)
+    Tuple[Optional[str], HttpxFileContent, Optional[str]],
+    # (filename, file (or bytes), content_type, headers)
+    Tuple[Optional[str], HttpxFileContent, Optional[str], Mapping[str, str]],
+]
+HttpxRequestFiles = Union[Mapping[str, HttpxFileTypes], Sequence[Tuple[str, HttpxFileTypes]]]
+
+# Workaround to support (cast_to: Type[ResponseT]) -> ResponseT
+# where ResponseT includes `None`. In order to support directly
+# passing `None`, overloads would have to be defined for every
+# method that uses `ResponseT` which would lead to an unacceptable
+# amount of code duplication and make it unreadable. See _base_client.py
+# for example usage.
+#
+# This unfortunately means that you will either have
+# to import this type and pass it explicitly:
+#
+# from anthropic import NoneType
+# client.get('/foo', cast_to=NoneType)
+#
+# or build it yourself:
+#
+# client.get('/foo', cast_to=type(None))
+if TYPE_CHECKING:
+    NoneType: Type[None]
+else:
+    NoneType = type(None)
+
+
+class RequestOptions(TypedDict, total=False):
+    headers: Headers
+    max_retries: int
+    timeout: float | Timeout | None
+    params: Query
+    extra_json: AnyMapping
+    idempotency_key: str
+
+
+# Sentinel class used until PEP 0661 is accepted
+class NotGiven:
+    """
+    A sentinel singleton class used to distinguish omitted keyword arguments
+    from those passed in with the value None (which may have different behavior).
+
+    For example:
+
+    ```py
+    def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: ...
+
+
+    get(timeout=1)  # 1s timeout
+    get(timeout=None)  # No timeout
+    get()  # Default timeout behavior, which may not be statically known at the method definition.
+    ```
+    """
+
+    def __bool__(self) -> Literal[False]:
+        return False
+
+    @override
+    def __repr__(self) -> str:
+        return "NOT_GIVEN"
+
+
+NotGivenOr = Union[_T, NotGiven]
+NOT_GIVEN = NotGiven()
+
+
+class Omit:
+    """In certain situations you need to be able to represent a case where a default value has
+    to be explicitly removed and `None` is not an appropriate substitute, for example:
+
+    ```py
+    # as the default `Content-Type` header is `application/json` that will be sent
+    client.post("/upload/files", files={"file": b"my raw file content"})
+
+    # you can't explicitly override the header as it has to be dynamically generated
+    # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983'
+    client.post(..., headers={"Content-Type": "multipart/form-data"})
+
+    # instead you can remove the default `application/json` header by passing Omit
+    client.post(..., headers={"Content-Type": Omit()})
+    ```
+    """
+
+    def __bool__(self) -> Literal[False]:
+        return False
+
+
+@runtime_checkable
+class ModelBuilderProtocol(Protocol):
+    @classmethod
+    def build(
+        cls: type[_T],
+        *,
+        response: Response,
+        data: object,
+    ) -> _T: ...
+
+
+Headers = Mapping[str, Union[str, Omit]]
+
+
+class HeadersLikeProtocol(Protocol):
+    def get(self, __key: str) -> str | None: ...
+
+
+HeadersLike = Union[Headers, HeadersLikeProtocol]
+
+ResponseT = TypeVar(
+    "ResponseT",
+    bound=Union[
+        object,
+        str,
+        None,
+        "BaseModel",
+        List[Any],
+        Dict[str, Any],
+        Response,
+        ModelBuilderProtocol,
+        "APIResponse[Any]",
+        "AsyncAPIResponse[Any]",
+        "HttpxBinaryResponseContent",
+    ],
+)
+
+StrBytesIntFloat = Union[str, bytes, int, float]
+
+# Note: copied from Pydantic
+# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79
+IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]]
+
+PostParser = Callable[[Any], Any]
+
+
+@runtime_checkable
+class InheritsGeneric(Protocol):
+    """Represents a type that has inherited from `Generic`
+
+    The `__orig_bases__` property can be used to determine the resolved
+    type variable for a given base class.
+    """
+
+    __orig_bases__: tuple[_GenericAlias]
+
+
+class _GenericAlias(Protocol):
+    __origin__: type[object]
+
+
+class HttpxSendArgs(TypedDict, total=False):
+    auth: httpx.Auth
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/__init__.py
new file mode 100644
index 00000000..d4fda26f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/__init__.py
@@ -0,0 +1,57 @@
+from ._sync import asyncify as asyncify
+from ._proxy import LazyProxy as LazyProxy
+from ._utils import (
+    flatten as flatten,
+    is_dict as is_dict,
+    is_list as is_list,
+    is_given as is_given,
+    is_tuple as is_tuple,
+    json_safe as json_safe,
+    lru_cache as lru_cache,
+    is_mapping as is_mapping,
+    is_tuple_t as is_tuple_t,
+    parse_date as parse_date,
+    is_iterable as is_iterable,
+    is_sequence as is_sequence,
+    coerce_float as coerce_float,
+    is_mapping_t as is_mapping_t,
+    removeprefix as removeprefix,
+    removesuffix as removesuffix,
+    extract_files as extract_files,
+    is_sequence_t as is_sequence_t,
+    required_args as required_args,
+    coerce_boolean as coerce_boolean,
+    coerce_integer as coerce_integer,
+    file_from_path as file_from_path,
+    parse_datetime as parse_datetime,
+    strip_not_given as strip_not_given,
+    deepcopy_minimal as deepcopy_minimal,
+    get_async_library as get_async_library,
+    maybe_coerce_float as maybe_coerce_float,
+    get_required_header as get_required_header,
+    maybe_coerce_boolean as maybe_coerce_boolean,
+    maybe_coerce_integer as maybe_coerce_integer,
+)
+from ._typing import (
+    is_list_type as is_list_type,
+    is_union_type as is_union_type,
+    extract_type_arg as extract_type_arg,
+    is_iterable_type as is_iterable_type,
+    is_required_type as is_required_type,
+    is_annotated_type as is_annotated_type,
+    is_type_alias_type as is_type_alias_type,
+    strip_annotated_type as strip_annotated_type,
+    extract_type_var_from_base as extract_type_var_from_base,
+)
+from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator
+from ._transform import (
+    PropertyInfo as PropertyInfo,
+    transform as transform,
+    async_transform as async_transform,
+    maybe_transform as maybe_transform,
+    async_maybe_transform as async_maybe_transform,
+)
+from ._reflection import (
+    function_has_argument as function_has_argument,
+    assert_signatures_in_sync as assert_signatures_in_sync,
+)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_logs.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_logs.py
new file mode 100644
index 00000000..a409705b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_logs.py
@@ -0,0 +1,25 @@
+import os
+import logging
+
+logger: logging.Logger = logging.getLogger("anthropic")
+httpx_logger: logging.Logger = logging.getLogger("httpx")
+
+
+def _basic_config() -> None:
+    # e.g. [2023-10-05 14:12:26 - anthropic._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK"
+    logging.basicConfig(
+        format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s",
+        datefmt="%Y-%m-%d %H:%M:%S",
+    )
+
+
+def setup_logging() -> None:
+    env = os.environ.get("ANTHROPIC_LOG")
+    if env == "debug":
+        _basic_config()
+        logger.setLevel(logging.DEBUG)
+        httpx_logger.setLevel(logging.DEBUG)
+    elif env == "info":
+        _basic_config()
+        logger.setLevel(logging.INFO)
+        httpx_logger.setLevel(logging.INFO)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_proxy.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_proxy.py
new file mode 100644
index 00000000..ffd883e9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_proxy.py
@@ -0,0 +1,62 @@
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+from typing import Generic, TypeVar, Iterable, cast
+from typing_extensions import override
+
+T = TypeVar("T")
+
+
+class LazyProxy(Generic[T], ABC):
+    """Implements data methods to pretend that an instance is another instance.
+
+    This includes forwarding attribute access and other methods.
+    """
+
+    # Note: we have to special case proxies that themselves return proxies
+    # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz`
+
+    def __getattr__(self, attr: str) -> object:
+        proxied = self.__get_proxied__()
+        if isinstance(proxied, LazyProxy):
+            return proxied  # pyright: ignore
+        return getattr(proxied, attr)
+
+    @override
+    def __repr__(self) -> str:
+        proxied = self.__get_proxied__()
+        if isinstance(proxied, LazyProxy):
+            return proxied.__class__.__name__
+        return repr(self.__get_proxied__())
+
+    @override
+    def __str__(self) -> str:
+        proxied = self.__get_proxied__()
+        if isinstance(proxied, LazyProxy):
+            return proxied.__class__.__name__
+        return str(proxied)
+
+    @override
+    def __dir__(self) -> Iterable[str]:
+        proxied = self.__get_proxied__()
+        if isinstance(proxied, LazyProxy):
+            return []
+        return proxied.__dir__()
+
+    @property  # type: ignore
+    @override
+    def __class__(self) -> type:  # pyright: ignore
+        proxied = self.__get_proxied__()
+        if issubclass(type(proxied), LazyProxy):
+            return type(proxied)
+        return proxied.__class__
+
+    def __get_proxied__(self) -> T:
+        return self.__load__()
+
+    def __as_proxied__(self) -> T:
+        """Helper method that returns the current proxy, typed as the loaded object"""
+        return cast(T, self)
+
+    @abstractmethod
+    def __load__(self) -> T: ...
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_reflection.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_reflection.py
new file mode 100644
index 00000000..89aa712a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_reflection.py
@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+import inspect
+from typing import Any, Callable
+
+
+def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool:
+    """Returns whether or not the given function has a specific parameter"""
+    sig = inspect.signature(func)
+    return arg_name in sig.parameters
+
+
+def assert_signatures_in_sync(
+    source_func: Callable[..., Any],
+    check_func: Callable[..., Any],
+    *,
+    exclude_params: set[str] = set(),
+) -> None:
+    """Ensure that the signature of the second function matches the first."""
+
+    check_sig = inspect.signature(check_func)
+    source_sig = inspect.signature(source_func)
+
+    errors: list[str] = []
+
+    for name, source_param in source_sig.parameters.items():
+        if name in exclude_params:
+            continue
+
+        custom_param = check_sig.parameters.get(name)
+        if not custom_param:
+            errors.append(f"the `{name}` param is missing")
+            continue
+
+        if custom_param.annotation != source_param.annotation:
+            errors.append(
+                f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}"
+            )
+            continue
+
+    if errors:
+        raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors))
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_streams.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_streams.py
new file mode 100644
index 00000000..f4a0208f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_streams.py
@@ -0,0 +1,12 @@
+from typing import Any
+from typing_extensions import Iterator, AsyncIterator
+
+
+def consume_sync_iterator(iterator: Iterator[Any]) -> None:
+    for _ in iterator:
+        ...
+
+
+async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None:
+    async for _ in iterator:
+        ...
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_sync.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_sync.py
new file mode 100644
index 00000000..ad7ec71b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_sync.py
@@ -0,0 +1,86 @@
+from __future__ import annotations
+
+import sys
+import asyncio
+import functools
+import contextvars
+from typing import Any, TypeVar, Callable, Awaitable
+from typing_extensions import ParamSpec
+
+import anyio
+import sniffio
+import anyio.to_thread
+
+T_Retval = TypeVar("T_Retval")
+T_ParamSpec = ParamSpec("T_ParamSpec")
+
+
+if sys.version_info >= (3, 9):
+    _asyncio_to_thread = asyncio.to_thread
+else:
+    # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
+    # for Python 3.8 support
+    async def _asyncio_to_thread(
+        func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
+    ) -> Any:
+        """Asynchronously run function *func* in a separate thread.
+
+        Any *args and **kwargs supplied for this function are directly passed
+        to *func*. Also, the current :class:`contextvars.Context` is propagated,
+        allowing context variables from the main thread to be accessed in the
+        separate thread.
+
+        Returns a coroutine that can be awaited to get the eventual result of *func*.
+        """
+        loop = asyncio.events.get_running_loop()
+        ctx = contextvars.copy_context()
+        func_call = functools.partial(ctx.run, func, *args, **kwargs)
+        return await loop.run_in_executor(None, func_call)
+
+
+async def to_thread(
+    func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
+) -> T_Retval:
+    if sniffio.current_async_library() == "asyncio":
+        return await _asyncio_to_thread(func, *args, **kwargs)
+
+    return await anyio.to_thread.run_sync(
+        functools.partial(func, *args, **kwargs),
+    )
+
+
+# inspired by `asyncer`, https://github.com/tiangolo/asyncer
+def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
+    """
+    Take a blocking function and create an async one that receives the same
+    positional and keyword arguments. For python version 3.9 and above, it uses
+    asyncio.to_thread to run the function in a separate thread. For python version
+    3.8, it uses locally defined copy of the asyncio.to_thread function which was
+    introduced in python 3.9.
+
+    Usage:
+
+    ```python
+    def blocking_func(arg1, arg2, kwarg1=None):
+        # blocking code
+        return result
+
+
+    result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1)
+    ```
+
+    ## Arguments
+
+    `function`: a blocking regular callable (e.g. a function)
+
+    ## Return
+
+    An async function that takes the same positional and keyword arguments as the
+    original one, that when called runs the same original function in a thread worker
+    and returns the result.
+    """
+
+    async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval:
+        return await to_thread(function, *args, **kwargs)
+
+    return wrapper
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_transform.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_transform.py
new file mode 100644
index 00000000..18afd9d8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_transform.py
@@ -0,0 +1,402 @@
+from __future__ import annotations
+
+import io
+import base64
+import pathlib
+from typing import Any, Mapping, TypeVar, cast
+from datetime import date, datetime
+from typing_extensions import Literal, get_args, override, get_type_hints
+
+import anyio
+import pydantic
+
+from ._utils import (
+    is_list,
+    is_mapping,
+    is_iterable,
+)
+from .._files import is_base64_file_input
+from ._typing import (
+    is_list_type,
+    is_union_type,
+    extract_type_arg,
+    is_iterable_type,
+    is_required_type,
+    is_annotated_type,
+    strip_annotated_type,
+)
+from .._compat import get_origin, model_dump, is_typeddict
+
+_T = TypeVar("_T")
+
+
+# TODO: support for drilling globals() and locals()
+# TODO: ensure works correctly with forward references in all cases
+
+
+PropertyFormat = Literal["iso8601", "base64", "custom"]
+
+
+class PropertyInfo:
+    """Metadata class to be used in Annotated types to provide information about a given type.
+
+    For example:
+
+    class MyParams(TypedDict):
+        account_holder_name: Annotated[str, PropertyInfo(alias='accountHolderName')]
+
+    This means that {'account_holder_name': 'Robert'} will be transformed to {'accountHolderName': 'Robert'} before being sent to the API.
+    """
+
+    alias: str | None
+    format: PropertyFormat | None
+    format_template: str | None
+    discriminator: str | None
+
+    def __init__(
+        self,
+        *,
+        alias: str | None = None,
+        format: PropertyFormat | None = None,
+        format_template: str | None = None,
+        discriminator: str | None = None,
+    ) -> None:
+        self.alias = alias
+        self.format = format
+        self.format_template = format_template
+        self.discriminator = discriminator
+
+    @override
+    def __repr__(self) -> str:
+        return f"{self.__class__.__name__}(alias='{self.alias}', format={self.format}, format_template='{self.format_template}', discriminator='{self.discriminator}')"
+
+
+def maybe_transform(
+    data: object,
+    expected_type: object,
+) -> Any | None:
+    """Wrapper over `transform()` that allows `None` to be passed.
+
+    See `transform()` for more details.
+    """
+    if data is None:
+        return None
+    return transform(data, expected_type)
+
+
+# Wrapper over _transform_recursive providing fake types
+def transform(
+    data: _T,
+    expected_type: object,
+) -> _T:
+    """Transform dictionaries based off of type information from the given type, for example:
+
+    ```py
+    class Params(TypedDict, total=False):
+        card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]]
+
+
+    transformed = transform({"card_id": "<my card ID>"}, Params)
+    # {'cardID': '<my card ID>'}
+    ```
+
+    Any keys / data that does not have type information given will be included as is.
+
+    It should be noted that the transformations that this function does are not represented in the type system.
+    """
+    transformed = _transform_recursive(data, annotation=cast(type, expected_type))
+    return cast(_T, transformed)
+
+
+def _get_annotated_type(type_: type) -> type | None:
+    """If the given type is an `Annotated` type then it is returned, if not `None` is returned.
+
+    This also unwraps the type when applicable, e.g. `Required[Annotated[T, ...]]`
+    """
+    if is_required_type(type_):
+        # Unwrap `Required[Annotated[T, ...]]` to `Annotated[T, ...]`
+        type_ = get_args(type_)[0]
+
+    if is_annotated_type(type_):
+        return type_
+
+    return None
+
+
+def _maybe_transform_key(key: str, type_: type) -> str:
+    """Transform the given `data` based on the annotations provided in `type_`.
+
+    Note: this function only looks at `Annotated` types that contain `PropertInfo` metadata.
+    """
+    annotated_type = _get_annotated_type(type_)
+    if annotated_type is None:
+        # no `Annotated` definition for this type, no transformation needed
+        return key
+
+    # ignore the first argument as it is the actual type
+    annotations = get_args(annotated_type)[1:]
+    for annotation in annotations:
+        if isinstance(annotation, PropertyInfo) and annotation.alias is not None:
+            return annotation.alias
+
+    return key
+
+
+def _transform_recursive(
+    data: object,
+    *,
+    annotation: type,
+    inner_type: type | None = None,
+) -> object:
+    """Transform the given data against the expected type.
+
+    Args:
+        annotation: The direct type annotation given to the particular piece of data.
+            This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc
+
+        inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type
+            is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in
+            the list can be transformed using the metadata from the container type.
+
+            Defaults to the same value as the `annotation` argument.
+    """
+    if inner_type is None:
+        inner_type = annotation
+
+    stripped_type = strip_annotated_type(inner_type)
+    origin = get_origin(stripped_type) or stripped_type
+    if is_typeddict(stripped_type) and is_mapping(data):
+        return _transform_typeddict(data, stripped_type)
+
+    if origin == dict and is_mapping(data):
+        items_type = get_args(stripped_type)[1]
+        return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()}
+
+    if (
+        # List[T]
+        (is_list_type(stripped_type) and is_list(data))
+        # Iterable[T]
+        or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str))
+    ):
+        # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually
+        # intended as an iterable, so we don't transform it.
+        if isinstance(data, dict):
+            return cast(object, data)
+
+        inner_type = extract_type_arg(stripped_type, 0)
+        return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data]
+
+    if is_union_type(stripped_type):
+        # For union types we run the transformation against all subtypes to ensure that everything is transformed.
+        #
+        # TODO: there may be edge cases where the same normalized field name will transform to two different names
+        # in different subtypes.
+        for subtype in get_args(stripped_type):
+            data = _transform_recursive(data, annotation=annotation, inner_type=subtype)
+        return data
+
+    if isinstance(data, pydantic.BaseModel):
+        return model_dump(data, exclude_unset=True, mode="json")
+
+    annotated_type = _get_annotated_type(annotation)
+    if annotated_type is None:
+        return data
+
+    # ignore the first argument as it is the actual type
+    annotations = get_args(annotated_type)[1:]
+    for annotation in annotations:
+        if isinstance(annotation, PropertyInfo) and annotation.format is not None:
+            return _format_data(data, annotation.format, annotation.format_template)
+
+    return data
+
+
+def _format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object:
+    if isinstance(data, (date, datetime)):
+        if format_ == "iso8601":
+            return data.isoformat()
+
+        if format_ == "custom" and format_template is not None:
+            return data.strftime(format_template)
+
+    if format_ == "base64" and is_base64_file_input(data):
+        binary: str | bytes | None = None
+
+        if isinstance(data, pathlib.Path):
+            binary = data.read_bytes()
+        elif isinstance(data, io.IOBase):
+            binary = data.read()
+
+            if isinstance(binary, str):  # type: ignore[unreachable]
+                binary = binary.encode()
+
+        if not isinstance(binary, bytes):
+            raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}")
+
+        return base64.b64encode(binary).decode("ascii")
+
+    return data
+
+
+def _transform_typeddict(
+    data: Mapping[str, object],
+    expected_type: type,
+) -> Mapping[str, object]:
+    result: dict[str, object] = {}
+    annotations = get_type_hints(expected_type, include_extras=True)
+    for key, value in data.items():
+        type_ = annotations.get(key)
+        if type_ is None:
+            # we do not have a type annotation for this field, leave it as is
+            result[key] = value
+        else:
+            result[_maybe_transform_key(key, type_)] = _transform_recursive(value, annotation=type_)
+    return result
+
+
+async def async_maybe_transform(
+    data: object,
+    expected_type: object,
+) -> Any | None:
+    """Wrapper over `async_transform()` that allows `None` to be passed.
+
+    See `async_transform()` for more details.
+    """
+    if data is None:
+        return None
+    return await async_transform(data, expected_type)
+
+
+async def async_transform(
+    data: _T,
+    expected_type: object,
+) -> _T:
+    """Transform dictionaries based off of type information from the given type, for example:
+
+    ```py
+    class Params(TypedDict, total=False):
+        card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]]
+
+
+    transformed = transform({"card_id": "<my card ID>"}, Params)
+    # {'cardID': '<my card ID>'}
+    ```
+
+    Any keys / data that does not have type information given will be included as is.
+
+    It should be noted that the transformations that this function does are not represented in the type system.
+    """
+    transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type))
+    return cast(_T, transformed)
+
+
+async def _async_transform_recursive(
+    data: object,
+    *,
+    annotation: type,
+    inner_type: type | None = None,
+) -> object:
+    """Transform the given data against the expected type.
+
+    Args:
+        annotation: The direct type annotation given to the particular piece of data.
+            This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc
+
+        inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type
+            is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in
+            the list can be transformed using the metadata from the container type.
+
+            Defaults to the same value as the `annotation` argument.
+    """
+    if inner_type is None:
+        inner_type = annotation
+
+    stripped_type = strip_annotated_type(inner_type)
+    origin = get_origin(stripped_type) or stripped_type
+    if is_typeddict(stripped_type) and is_mapping(data):
+        return await _async_transform_typeddict(data, stripped_type)
+
+    if origin == dict and is_mapping(data):
+        items_type = get_args(stripped_type)[1]
+        return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()}
+
+    if (
+        # List[T]
+        (is_list_type(stripped_type) and is_list(data))
+        # Iterable[T]
+        or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str))
+    ):
+        # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually
+        # intended as an iterable, so we don't transform it.
+        if isinstance(data, dict):
+            return cast(object, data)
+
+        inner_type = extract_type_arg(stripped_type, 0)
+        return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data]
+
+    if is_union_type(stripped_type):
+        # For union types we run the transformation against all subtypes to ensure that everything is transformed.
+        #
+        # TODO: there may be edge cases where the same normalized field name will transform to two different names
+        # in different subtypes.
+        for subtype in get_args(stripped_type):
+            data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype)
+        return data
+
+    if isinstance(data, pydantic.BaseModel):
+        return model_dump(data, exclude_unset=True, mode="json")
+
+    annotated_type = _get_annotated_type(annotation)
+    if annotated_type is None:
+        return data
+
+    # ignore the first argument as it is the actual type
+    annotations = get_args(annotated_type)[1:]
+    for annotation in annotations:
+        if isinstance(annotation, PropertyInfo) and annotation.format is not None:
+            return await _async_format_data(data, annotation.format, annotation.format_template)
+
+    return data
+
+
+async def _async_format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object:
+    if isinstance(data, (date, datetime)):
+        if format_ == "iso8601":
+            return data.isoformat()
+
+        if format_ == "custom" and format_template is not None:
+            return data.strftime(format_template)
+
+    if format_ == "base64" and is_base64_file_input(data):
+        binary: str | bytes | None = None
+
+        if isinstance(data, pathlib.Path):
+            binary = await anyio.Path(data).read_bytes()
+        elif isinstance(data, io.IOBase):
+            binary = data.read()
+
+            if isinstance(binary, str):  # type: ignore[unreachable]
+                binary = binary.encode()
+
+        if not isinstance(binary, bytes):
+            raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}")
+
+        return base64.b64encode(binary).decode("ascii")
+
+    return data
+
+
+async def _async_transform_typeddict(
+    data: Mapping[str, object],
+    expected_type: type,
+) -> Mapping[str, object]:
+    result: dict[str, object] = {}
+    annotations = get_type_hints(expected_type, include_extras=True)
+    for key, value in data.items():
+        type_ = annotations.get(key)
+        if type_ is None:
+            # we do not have a type annotation for this field, leave it as is
+            result[key] = value
+        else:
+            result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_)
+    return result
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_typing.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_typing.py
new file mode 100644
index 00000000..278749b1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_typing.py
@@ -0,0 +1,149 @@
+from __future__ import annotations
+
+import sys
+import typing
+import typing_extensions
+from typing import Any, TypeVar, Iterable, cast
+from collections import abc as _c_abc
+from typing_extensions import (
+    TypeIs,
+    Required,
+    Annotated,
+    get_args,
+    get_origin,
+)
+
+from .._types import InheritsGeneric
+from .._compat import is_union as _is_union
+
+
+def is_annotated_type(typ: type) -> bool:
+    return get_origin(typ) == Annotated
+
+
+def is_list_type(typ: type) -> bool:
+    return (get_origin(typ) or typ) == list
+
+
+def is_iterable_type(typ: type) -> bool:
+    """If the given type is `typing.Iterable[T]`"""
+    origin = get_origin(typ) or typ
+    return origin == Iterable or origin == _c_abc.Iterable
+
+
+def is_union_type(typ: type) -> bool:
+    return _is_union(get_origin(typ))
+
+
+def is_required_type(typ: type) -> bool:
+    return get_origin(typ) == Required
+
+
+def is_typevar(typ: type) -> bool:
+    # type ignore is required because type checkers
+    # think this expression will always return False
+    return type(typ) == TypeVar  # type: ignore
+
+
+_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,)
+if sys.version_info >= (3, 12):
+    _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType)
+
+
+def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]:
+    """Return whether the provided argument is an instance of `TypeAliasType`.
+
+    ```python
+    type Int = int
+    is_type_alias_type(Int)
+    # > True
+    Str = TypeAliasType("Str", str)
+    is_type_alias_type(Str)
+    # > True
+    ```
+    """
+    return isinstance(tp, _TYPE_ALIAS_TYPES)
+
+
+# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]]
+def strip_annotated_type(typ: type) -> type:
+    if is_required_type(typ) or is_annotated_type(typ):
+        return strip_annotated_type(cast(type, get_args(typ)[0]))
+
+    return typ
+
+
+def extract_type_arg(typ: type, index: int) -> type:
+    args = get_args(typ)
+    try:
+        return cast(type, args[index])
+    except IndexError as err:
+        raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err
+
+
+def extract_type_var_from_base(
+    typ: type,
+    *,
+    generic_bases: tuple[type, ...],
+    index: int,
+    failure_message: str | None = None,
+) -> type:
+    """Given a type like `Foo[T]`, returns the generic type variable `T`.
+
+    This also handles the case where a concrete subclass is given, e.g.
+    ```py
+    class MyResponse(Foo[bytes]):
+        ...
+
+    extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes
+    ```
+
+    And where a generic subclass is given:
+    ```py
+    _T = TypeVar('_T')
+    class MyResponse(Foo[_T]):
+        ...
+
+    extract_type_var(MyResponse[bytes], bases=(Foo,), index=0) -> bytes
+    ```
+    """
+    cls = cast(object, get_origin(typ) or typ)
+    if cls in generic_bases:
+        # we're given the class directly
+        return extract_type_arg(typ, index)
+
+    # if a subclass is given
+    # ---
+    # this is needed as __orig_bases__ is not present in the typeshed stubs
+    # because it is intended to be for internal use only, however there does
+    # not seem to be a way to resolve generic TypeVars for inherited subclasses
+    # without using it.
+    if isinstance(cls, InheritsGeneric):
+        target_base_class: Any | None = None
+        for base in cls.__orig_bases__:
+            if base.__origin__ in generic_bases:
+                target_base_class = base
+                break
+
+        if target_base_class is None:
+            raise RuntimeError(
+                "Could not find the generic base class;\n"
+                "This should never happen;\n"
+                f"Does {cls} inherit from one of {generic_bases} ?"
+            )
+
+        extracted = extract_type_arg(target_base_class, index)
+        if is_typevar(extracted):
+            # If the extracted type argument is itself a type variable
+            # then that means the subclass itself is generic, so we have
+            # to resolve the type argument from the class itself, not
+            # the base class.
+            #
+            # Note: if there is more than 1 type argument, the subclass could
+            # change the ordering of the type arguments, this is not currently
+            # supported.
+            return extract_type_arg(typ, index)
+
+        return extracted
+
+    raise RuntimeError(failure_message or f"Could not resolve inner type variable at index {index} for {typ}")
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_utils/_utils.py b/.venv/lib/python3.12/site-packages/anthropic/_utils/_utils.py
new file mode 100644
index 00000000..e5811bba
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_utils/_utils.py
@@ -0,0 +1,414 @@
+from __future__ import annotations
+
+import os
+import re
+import inspect
+import functools
+from typing import (
+    Any,
+    Tuple,
+    Mapping,
+    TypeVar,
+    Callable,
+    Iterable,
+    Sequence,
+    cast,
+    overload,
+)
+from pathlib import Path
+from datetime import date, datetime
+from typing_extensions import TypeGuard
+
+import sniffio
+
+from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike
+from .._compat import parse_date as parse_date, parse_datetime as parse_datetime
+
+_T = TypeVar("_T")
+_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...])
+_MappingT = TypeVar("_MappingT", bound=Mapping[str, object])
+_SequenceT = TypeVar("_SequenceT", bound=Sequence[object])
+CallableT = TypeVar("CallableT", bound=Callable[..., Any])
+
+
+def flatten(t: Iterable[Iterable[_T]]) -> list[_T]:
+    return [item for sublist in t for item in sublist]
+
+
+def extract_files(
+    # TODO: this needs to take Dict but variance issues.....
+    # create protocol type ?
+    query: Mapping[str, object],
+    *,
+    paths: Sequence[Sequence[str]],
+) -> list[tuple[str, FileTypes]]:
+    """Recursively extract files from the given dictionary based on specified paths.
+
+    A path may look like this ['foo', 'files', '<array>', 'data'].
+
+    Note: this mutates the given dictionary.
+    """
+    files: list[tuple[str, FileTypes]] = []
+    for path in paths:
+        files.extend(_extract_items(query, path, index=0, flattened_key=None))
+    return files
+
+
+def _extract_items(
+    obj: object,
+    path: Sequence[str],
+    *,
+    index: int,
+    flattened_key: str | None,
+) -> list[tuple[str, FileTypes]]:
+    try:
+        key = path[index]
+    except IndexError:
+        if isinstance(obj, NotGiven):
+            # no value was provided - we can safely ignore
+            return []
+
+        # cyclical import
+        from .._files import assert_is_file_content
+
+        # We have exhausted the path, return the entry we found.
+        assert_is_file_content(obj, key=flattened_key)
+        assert flattened_key is not None
+        return [(flattened_key, cast(FileTypes, obj))]
+
+    index += 1
+    if is_dict(obj):
+        try:
+            # We are at the last entry in the path so we must remove the field
+            if (len(path)) == index:
+                item = obj.pop(key)
+            else:
+                item = obj[key]
+        except KeyError:
+            # Key was not present in the dictionary, this is not indicative of an error
+            # as the given path may not point to a required field. We also do not want
+            # to enforce required fields as the API may differ from the spec in some cases.
+            return []
+        if flattened_key is None:
+            flattened_key = key
+        else:
+            flattened_key += f"[{key}]"
+        return _extract_items(
+            item,
+            path,
+            index=index,
+            flattened_key=flattened_key,
+        )
+    elif is_list(obj):
+        if key != "<array>":
+            return []
+
+        return flatten(
+            [
+                _extract_items(
+                    item,
+                    path,
+                    index=index,
+                    flattened_key=flattened_key + "[]" if flattened_key is not None else "[]",
+                )
+                for item in obj
+            ]
+        )
+
+    # Something unexpected was passed, just ignore it.
+    return []
+
+
+def is_given(obj: NotGivenOr[_T]) -> TypeGuard[_T]:
+    return not isinstance(obj, NotGiven)
+
+
+# Type safe methods for narrowing types with TypeVars.
+# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown],
+# however this cause Pyright to rightfully report errors. As we know we don't
+# care about the contained types we can safely use `object` in it's place.
+#
+# There are two separate functions defined, `is_*` and `is_*_t` for different use cases.
+# `is_*` is for when you're dealing with an unknown input
+# `is_*_t` is for when you're narrowing a known union type to a specific subset
+
+
+def is_tuple(obj: object) -> TypeGuard[tuple[object, ...]]:
+    return isinstance(obj, tuple)
+
+
+def is_tuple_t(obj: _TupleT | object) -> TypeGuard[_TupleT]:
+    return isinstance(obj, tuple)
+
+
+def is_sequence(obj: object) -> TypeGuard[Sequence[object]]:
+    return isinstance(obj, Sequence)
+
+
+def is_sequence_t(obj: _SequenceT | object) -> TypeGuard[_SequenceT]:
+    return isinstance(obj, Sequence)
+
+
+def is_mapping(obj: object) -> TypeGuard[Mapping[str, object]]:
+    return isinstance(obj, Mapping)
+
+
+def is_mapping_t(obj: _MappingT | object) -> TypeGuard[_MappingT]:
+    return isinstance(obj, Mapping)
+
+
+def is_dict(obj: object) -> TypeGuard[dict[object, object]]:
+    return isinstance(obj, dict)
+
+
+def is_list(obj: object) -> TypeGuard[list[object]]:
+    return isinstance(obj, list)
+
+
+def is_iterable(obj: object) -> TypeGuard[Iterable[object]]:
+    return isinstance(obj, Iterable)
+
+
+def deepcopy_minimal(item: _T) -> _T:
+    """Minimal reimplementation of copy.deepcopy() that will only copy certain object types:
+
+    - mappings, e.g. `dict`
+    - list
+
+    This is done for performance reasons.
+    """
+    if is_mapping(item):
+        return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()})
+    if is_list(item):
+        return cast(_T, [deepcopy_minimal(entry) for entry in item])
+    return item
+
+
+# copied from https://github.com/Rapptz/RoboDanny
+def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str:
+    size = len(seq)
+    if size == 0:
+        return ""
+
+    if size == 1:
+        return seq[0]
+
+    if size == 2:
+        return f"{seq[0]} {final} {seq[1]}"
+
+    return delim.join(seq[:-1]) + f" {final} {seq[-1]}"
+
+
+def quote(string: str) -> str:
+    """Add single quotation marks around the given string. Does *not* do any escaping."""
+    return f"'{string}'"
+
+
+def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]:
+    """Decorator to enforce a given set of arguments or variants of arguments are passed to the decorated function.
+
+    Useful for enforcing runtime validation of overloaded functions.
+
+    Example usage:
+    ```py
+    @overload
+    def foo(*, a: str) -> str: ...
+
+
+    @overload
+    def foo(*, b: bool) -> str: ...
+
+
+    # This enforces the same constraints that a static type checker would
+    # i.e. that either a or b must be passed to the function
+    @required_args(["a"], ["b"])
+    def foo(*, a: str | None = None, b: bool | None = None) -> str: ...
+    ```
+    """
+
+    def inner(func: CallableT) -> CallableT:
+        params = inspect.signature(func).parameters
+        positional = [
+            name
+            for name, param in params.items()
+            if param.kind
+            in {
+                param.POSITIONAL_ONLY,
+                param.POSITIONAL_OR_KEYWORD,
+            }
+        ]
+
+        @functools.wraps(func)
+        def wrapper(*args: object, **kwargs: object) -> object:
+            given_params: set[str] = set()
+            for i, _ in enumerate(args):
+                try:
+                    given_params.add(positional[i])
+                except IndexError:
+                    raise TypeError(
+                        f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given"
+                    ) from None
+
+            for key in kwargs.keys():
+                given_params.add(key)
+
+            for variant in variants:
+                matches = all((param in given_params for param in variant))
+                if matches:
+                    break
+            else:  # no break
+                if len(variants) > 1:
+                    variations = human_join(
+                        ["(" + human_join([quote(arg) for arg in variant], final="and") + ")" for variant in variants]
+                    )
+                    msg = f"Missing required arguments; Expected either {variations} arguments to be given"
+                else:
+                    assert len(variants) > 0
+
+                    # TODO: this error message is not deterministic
+                    missing = list(set(variants[0]) - given_params)
+                    if len(missing) > 1:
+                        msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}"
+                    else:
+                        msg = f"Missing required argument: {quote(missing[0])}"
+                raise TypeError(msg)
+            return func(*args, **kwargs)
+
+        return wrapper  # type: ignore
+
+    return inner
+
+
+_K = TypeVar("_K")
+_V = TypeVar("_V")
+
+
+@overload
+def strip_not_given(obj: None) -> None: ...
+
+
+@overload
+def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ...
+
+
+@overload
+def strip_not_given(obj: object) -> object: ...
+
+
+def strip_not_given(obj: object | None) -> object:
+    """Remove all top-level keys where their values are instances of `NotGiven`"""
+    if obj is None:
+        return None
+
+    if not is_mapping(obj):
+        return obj
+
+    return {key: value for key, value in obj.items() if not isinstance(value, NotGiven)}
+
+
+def coerce_integer(val: str) -> int:
+    return int(val, base=10)
+
+
+def coerce_float(val: str) -> float:
+    return float(val)
+
+
+def coerce_boolean(val: str) -> bool:
+    return val == "true" or val == "1" or val == "on"
+
+
+def maybe_coerce_integer(val: str | None) -> int | None:
+    if val is None:
+        return None
+    return coerce_integer(val)
+
+
+def maybe_coerce_float(val: str | None) -> float | None:
+    if val is None:
+        return None
+    return coerce_float(val)
+
+
+def maybe_coerce_boolean(val: str | None) -> bool | None:
+    if val is None:
+        return None
+    return coerce_boolean(val)
+
+
+def removeprefix(string: str, prefix: str) -> str:
+    """Remove a prefix from a string.
+
+    Backport of `str.removeprefix` for Python < 3.9
+    """
+    if string.startswith(prefix):
+        return string[len(prefix) :]
+    return string
+
+
+def removesuffix(string: str, suffix: str) -> str:
+    """Remove a suffix from a string.
+
+    Backport of `str.removesuffix` for Python < 3.9
+    """
+    if string.endswith(suffix):
+        return string[: -len(suffix)]
+    return string
+
+
+def file_from_path(path: str) -> FileTypes:
+    contents = Path(path).read_bytes()
+    file_name = os.path.basename(path)
+    return (file_name, contents)
+
+
+def get_required_header(headers: HeadersLike, header: str) -> str:
+    lower_header = header.lower()
+    if is_mapping_t(headers):
+        # mypy doesn't understand the type narrowing here
+        for k, v in headers.items():  # type: ignore
+            if k.lower() == lower_header and isinstance(v, str):
+                return v
+
+    # to deal with the case where the header looks like Stainless-Event-Id
+    intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize())
+
+    for normalized_header in [header, lower_header, header.upper(), intercaps_header]:
+        value = headers.get(normalized_header)
+        if value:
+            return value
+
+    raise ValueError(f"Could not find {header} header")
+
+
+def get_async_library() -> str:
+    try:
+        return sniffio.current_async_library()
+    except Exception:
+        return "false"
+
+
+def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]:
+    """A version of functools.lru_cache that retains the type signature
+    for the wrapped function arguments.
+    """
+    wrapper = functools.lru_cache(  # noqa: TID251
+        maxsize=maxsize,
+    )
+    return cast(Any, wrapper)  # type: ignore[no-any-return]
+
+
+def json_safe(data: object) -> object:
+    """Translates a mapping / sequence recursively in the same fashion
+    as `pydantic` v2's `model_dump(mode="json")`.
+    """
+    if is_mapping(data):
+        return {json_safe(key): json_safe(value) for key, value in data.items()}
+
+    if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)):
+        return [json_safe(item) for item in data]
+
+    if isinstance(data, (datetime, date)):
+        return data.isoformat()
+
+    return data
diff --git a/.venv/lib/python3.12/site-packages/anthropic/_version.py b/.venv/lib/python3.12/site-packages/anthropic/_version.py
new file mode 100644
index 00000000..181038b4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/_version.py
@@ -0,0 +1,4 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+__title__ = "anthropic"
+__version__ = "0.49.0"  # x-release-please-version
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/.keep b/.venv/lib/python3.12/site-packages/anthropic/lib/.keep
new file mode 100644
index 00000000..5e2c99fd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/.keep
@@ -0,0 +1,4 @@
+File generated from our OpenAPI spec by Stainless.
+
+This directory can be used to store custom files to expand the SDK.
+It is ignored by Stainless code generation and its content (other than this keep file) won't be touched.
\ No newline at end of file
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/lib/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/__init__.py
new file mode 100644
index 00000000..4e3037ee
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/__init__.py
@@ -0,0 +1 @@
+from ._google_auth import google_auth as google_auth
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_common.py b/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_common.py
new file mode 100644
index 00000000..5d2b7f6a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_common.py
@@ -0,0 +1,13 @@
+from ..._exceptions import AnthropicError
+
+INSTRUCTIONS = """
+
+Anthropic error: missing required dependency `{library}`.
+
+    $ pip install anthropic[{extra}]
+"""
+
+
+class MissingDependencyError(AnthropicError):
+    def __init__(self, *, library: str, extra: str) -> None:
+        super().__init__(INSTRUCTIONS.format(library=library, extra=extra))
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_google_auth.py b/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_google_auth.py
new file mode 100644
index 00000000..16cc7909
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/_extras/_google_auth.py
@@ -0,0 +1,29 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+from typing_extensions import ClassVar, override
+
+from ._common import MissingDependencyError
+from ..._utils import LazyProxy
+
+if TYPE_CHECKING:
+    import google.auth  # type: ignore
+
+    google_auth = google.auth
+
+
+class GoogleAuthProxy(LazyProxy[Any]):
+    should_cache: ClassVar[bool] = True
+
+    @override
+    def __load__(self) -> Any:
+        try:
+            import google.auth  # type: ignore
+        except ImportError as err:
+            raise MissingDependencyError(extra="vertex", library="google-auth") from err
+
+        return google.auth
+
+
+if not TYPE_CHECKING:
+    google_auth = GoogleAuthProxy()
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/__init__.py
new file mode 100644
index 00000000..69440c76
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/__init__.py
@@ -0,0 +1 @@
+from ._client import AnthropicBedrock as AnthropicBedrock, AsyncAnthropicBedrock as AsyncAnthropicBedrock
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_auth.py b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_auth.py
new file mode 100644
index 00000000..0a8b2109
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_auth.py
@@ -0,0 +1,72 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import httpx
+
+from ..._utils import lru_cache
+
+if TYPE_CHECKING:
+    import boto3
+
+
+@lru_cache(maxsize=512)
+def _get_session(
+    *,
+    aws_access_key: str | None,
+    aws_secret_key: str | None,
+    aws_session_token: str | None,
+    region: str | None,
+    profile: str | None,
+) -> boto3.Session:
+    import boto3
+
+    return boto3.Session(
+        profile_name=profile,
+        region_name=region,
+        aws_access_key_id=aws_access_key,
+        aws_secret_access_key=aws_secret_key,
+        aws_session_token=aws_session_token,
+    )
+
+
+def get_auth_headers(
+    *,
+    method: str,
+    url: str,
+    headers: httpx.Headers,
+    aws_access_key: str | None,
+    aws_secret_key: str | None,
+    aws_session_token: str | None,
+    region: str | None,
+    profile: str | None,
+    data: str | None,
+) -> dict[str, str]:
+    from botocore.auth import SigV4Auth
+    from botocore.awsrequest import AWSRequest
+
+    session = _get_session(
+        profile=profile,
+        region=region,
+        aws_access_key=aws_access_key,
+        aws_secret_key=aws_secret_key,
+        aws_session_token=aws_session_token,
+    )
+
+    # The connection header may be stripped by a proxy somewhere, so the receiver
+    # of this message may not see this header, so we remove it from the set of headers
+    # that are signed.
+    headers = headers.copy()
+    del headers["connection"]
+
+    request = AWSRequest(method=method.upper(), url=url, headers=headers, data=data)
+    credentials = session.get_credentials()
+    if not credentials:
+        raise RuntimeError("could not resolve credentials from session")
+
+    signer = SigV4Auth(credentials, "bedrock", session.region_name)
+    signer.add_auth(request)
+
+    prepped = request.prepare()
+
+    return {key: value for key, value in dict(prepped.headers).items() if value is not None}
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta.py b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta.py
new file mode 100644
index 00000000..f2a91b42
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta.py
@@ -0,0 +1,102 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ._beta_messages import (
+    Messages,
+    AsyncMessages,
+    MessagesWithRawResponse,
+    AsyncMessagesWithRawResponse,
+    MessagesWithStreamingResponse,
+    AsyncMessagesWithStreamingResponse,
+)
+
+__all__ = ["Beta", "AsyncBeta"]
+
+
+class Beta(SyncAPIResource):
+    @cached_property
+    def messages(self) -> Messages:
+        return Messages(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> BetaWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return BetaWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> BetaWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return BetaWithStreamingResponse(self)
+
+
+class AsyncBeta(AsyncAPIResource):
+    @cached_property
+    def messages(self) -> AsyncMessages:
+        return AsyncMessages(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> AsyncBetaWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncBetaWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncBetaWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncBetaWithStreamingResponse(self)
+
+
+class BetaWithRawResponse:
+    def __init__(self, beta: Beta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> MessagesWithRawResponse:
+        return MessagesWithRawResponse(self._beta.messages)
+
+
+class AsyncBetaWithRawResponse:
+    def __init__(self, beta: AsyncBeta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> AsyncMessagesWithRawResponse:
+        return AsyncMessagesWithRawResponse(self._beta.messages)
+
+
+class BetaWithStreamingResponse:
+    def __init__(self, beta: Beta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> MessagesWithStreamingResponse:
+        return MessagesWithStreamingResponse(self._beta.messages)
+
+
+class AsyncBetaWithStreamingResponse:
+    def __init__(self, beta: AsyncBeta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> AsyncMessagesWithStreamingResponse:
+        return AsyncMessagesWithStreamingResponse(self._beta.messages)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta_messages.py b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta_messages.py
new file mode 100644
index 00000000..332f6fba
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_beta_messages.py
@@ -0,0 +1,93 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ... import _legacy_response
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...resources.beta import Messages as FirstPartyMessagesAPI, AsyncMessages as FirstPartyAsyncMessagesAPI
+
+__all__ = ["Messages", "AsyncMessages"]
+
+
+class Messages(SyncAPIResource):
+    create = FirstPartyMessagesAPI.create
+
+    @cached_property
+    def with_raw_response(self) -> MessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return MessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> MessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return MessagesWithStreamingResponse(self)
+
+
+class AsyncMessages(AsyncAPIResource):
+    create = FirstPartyAsyncMessagesAPI.create
+
+    @cached_property
+    def with_raw_response(self) -> AsyncMessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncMessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncMessagesWithStreamingResponse(self)
+
+
+class MessagesWithRawResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.to_raw_response_wrapper(
+            messages.create,
+        )
+
+
+class AsyncMessagesWithRawResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.async_to_raw_response_wrapper(
+            messages.create,
+        )
+
+
+class MessagesWithStreamingResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = to_streamed_response_wrapper(
+            messages.create,
+        )
+
+
+class AsyncMessagesWithStreamingResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = async_to_streamed_response_wrapper(
+            messages.create,
+        )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_client.py b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_client.py
new file mode 100644
index 00000000..ca645489
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_client.py
@@ -0,0 +1,390 @@
+from __future__ import annotations
+
+import os
+import urllib.parse
+from typing import Any, Union, Mapping, TypeVar
+from typing_extensions import Self, override
+
+import httpx
+
+from ... import _exceptions
+from ._beta import Beta, AsyncBeta
+from ..._types import NOT_GIVEN, Timeout, NotGiven
+from ..._utils import is_dict, is_given
+from ..._compat import model_copy
+from ..._version import __version__
+from ..._streaming import Stream, AsyncStream
+from ..._exceptions import AnthropicError, APIStatusError
+from ..._base_client import (
+    DEFAULT_MAX_RETRIES,
+    BaseClient,
+    SyncAPIClient,
+    AsyncAPIClient,
+    FinalRequestOptions,
+)
+from ._stream_decoder import AWSEventStreamDecoder
+from ...resources.messages import Messages, AsyncMessages
+from ...resources.completions import Completions, AsyncCompletions
+
+DEFAULT_VERSION = "bedrock-2023-05-31"
+
+_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient])
+_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]])
+
+
+def _prepare_options(input_options: FinalRequestOptions) -> FinalRequestOptions:
+    options = model_copy(input_options, deep=True)
+
+    if is_dict(options.json_data):
+        options.json_data.setdefault("anthropic_version", DEFAULT_VERSION)
+
+        if is_given(options.headers):
+            betas = options.headers.get("anthropic-beta")
+            if betas:
+                options.json_data.setdefault("anthropic_beta", betas.split(","))
+
+    if options.url in {"/v1/complete", "/v1/messages", "/v1/messages?beta=true"} and options.method == "post":
+        if not is_dict(options.json_data):
+            raise RuntimeError("Expected dictionary json_data for post /completions endpoint")
+
+        model = options.json_data.pop("model", None)
+        model = urllib.parse.quote(str(model), safe=":")
+        stream = options.json_data.pop("stream", False)
+        if stream:
+            options.url = f"/model/{model}/invoke-with-response-stream"
+        else:
+            options.url = f"/model/{model}/invoke"
+
+    if options.url.startswith("/v1/messages/batches"):
+        raise AnthropicError("The Batch API is not supported in Bedrock yet")
+
+    if options.url == "/v1/messages/count_tokens":
+        raise AnthropicError("Token counting is not supported in Bedrock yet")
+
+    return options
+
+
+class BaseBedrockClient(BaseClient[_HttpxClientT, _DefaultStreamT]):
+    @override
+    def _make_status_error(
+        self,
+        err_msg: str,
+        *,
+        body: object,
+        response: httpx.Response,
+    ) -> APIStatusError:
+        if response.status_code == 400:
+            return _exceptions.BadRequestError(err_msg, response=response, body=body)
+
+        if response.status_code == 401:
+            return _exceptions.AuthenticationError(err_msg, response=response, body=body)
+
+        if response.status_code == 403:
+            return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)
+
+        if response.status_code == 404:
+            return _exceptions.NotFoundError(err_msg, response=response, body=body)
+
+        if response.status_code == 409:
+            return _exceptions.ConflictError(err_msg, response=response, body=body)
+
+        if response.status_code == 422:
+            return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)
+
+        if response.status_code == 429:
+            return _exceptions.RateLimitError(err_msg, response=response, body=body)
+
+        if response.status_code == 503:
+            return _exceptions.ServiceUnavailableError(err_msg, response=response, body=body)
+
+        if response.status_code >= 500:
+            return _exceptions.InternalServerError(err_msg, response=response, body=body)
+        return APIStatusError(err_msg, response=response, body=body)
+
+
+class AnthropicBedrock(BaseBedrockClient[httpx.Client, Stream[Any]], SyncAPIClient):
+    messages: Messages
+    completions: Completions
+    beta: Beta
+
+    def __init__(
+        self,
+        aws_secret_key: str | None = None,
+        aws_access_key: str | None = None,
+        aws_region: str | None = None,
+        aws_profile: str | None = None,
+        aws_session_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        # Configure a custom httpx client. See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
+        http_client: httpx.Client | None = None,
+        # Enable or disable schema validation for data returned by the API.
+        # When enabled an error APIResponseValidationError is raised
+        # if the API responds with invalid data for the expected schema.
+        #
+        # This parameter may be removed or changed in the future.
+        # If you rely on this feature, please open a GitHub issue
+        # outlining your use-case to help us decide if it should be
+        # part of our public interface in the future.
+        _strict_response_validation: bool = False,
+    ) -> None:
+        self.aws_secret_key = aws_secret_key
+
+        self.aws_access_key = aws_access_key
+
+        if aws_region is None:
+            aws_region = os.environ.get("AWS_REGION") or "us-east-1"
+        self.aws_region = aws_region
+        self.aws_profile = aws_profile
+
+        self.aws_session_token = aws_session_token
+
+        if base_url is None:
+            base_url = os.environ.get("ANTHROPIC_BEDROCK_BASE_URL")
+        if base_url is None:
+            base_url = f"https://bedrock-runtime.{self.aws_region}.amazonaws.com"
+
+        super().__init__(
+            version=__version__,
+            base_url=base_url,
+            timeout=timeout,
+            max_retries=max_retries,
+            custom_headers=default_headers,
+            custom_query=default_query,
+            http_client=http_client,
+            _strict_response_validation=_strict_response_validation,
+        )
+
+        self.beta = Beta(self)
+        self.messages = Messages(self)
+        self.completions = Completions(self)
+
+    @override
+    def _make_sse_decoder(self) -> AWSEventStreamDecoder:
+        return AWSEventStreamDecoder()
+
+    @override
+    def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
+        return _prepare_options(options)
+
+    @override
+    def _prepare_request(self, request: httpx.Request) -> None:
+        from ._auth import get_auth_headers
+
+        data = request.read().decode()
+
+        headers = get_auth_headers(
+            method=request.method,
+            url=str(request.url),
+            headers=request.headers,
+            aws_access_key=self.aws_access_key,
+            aws_secret_key=self.aws_secret_key,
+            aws_session_token=self.aws_session_token,
+            region=self.aws_region or "us-east-1",
+            profile=self.aws_profile,
+            data=data,
+        )
+        request.headers.update(headers)
+
+    def copy(
+        self,
+        *,
+        aws_secret_key: str | None = None,
+        aws_access_key: str | None = None,
+        aws_region: str | None = None,
+        aws_session_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
+        http_client: httpx.Client | None = None,
+        max_retries: int | NotGiven = NOT_GIVEN,
+        default_headers: Mapping[str, str] | None = None,
+        set_default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        set_default_query: Mapping[str, object] | None = None,
+        _extra_kwargs: Mapping[str, Any] = {},
+    ) -> Self:
+        """
+        Create a new client instance re-using the same options given to the current client with optional overriding.
+        """
+        if default_headers is not None and set_default_headers is not None:
+            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")
+
+        if default_query is not None and set_default_query is not None:
+            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")
+
+        headers = self._custom_headers
+        if default_headers is not None:
+            headers = {**headers, **default_headers}
+        elif set_default_headers is not None:
+            headers = set_default_headers
+
+        params = self._custom_query
+        if default_query is not None:
+            params = {**params, **default_query}
+        elif set_default_query is not None:
+            params = set_default_query
+
+        return self.__class__(
+            aws_secret_key=aws_secret_key or self.aws_secret_key,
+            aws_access_key=aws_access_key or self.aws_access_key,
+            aws_region=aws_region or self.aws_region,
+            aws_session_token=aws_session_token or self.aws_session_token,
+            base_url=base_url or self.base_url,
+            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
+            http_client=http_client,
+            max_retries=max_retries if is_given(max_retries) else self.max_retries,
+            default_headers=headers,
+            default_query=params,
+            **_extra_kwargs,
+        )
+
+    # Alias for `copy` for nicer inline usage, e.g.
+    # client.with_options(timeout=10).foo.create(...)
+    with_options = copy
+
+
+class AsyncAnthropicBedrock(BaseBedrockClient[httpx.AsyncClient, AsyncStream[Any]], AsyncAPIClient):
+    messages: AsyncMessages
+    completions: AsyncCompletions
+    beta: AsyncBeta
+
+    def __init__(
+        self,
+        aws_secret_key: str | None = None,
+        aws_access_key: str | None = None,
+        aws_region: str | None = None,
+        aws_profile: str | None = None,
+        aws_session_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        # Configure a custom httpx client. See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
+        http_client: httpx.AsyncClient | None = None,
+        # Enable or disable schema validation for data returned by the API.
+        # When enabled an error APIResponseValidationError is raised
+        # if the API responds with invalid data for the expected schema.
+        #
+        # This parameter may be removed or changed in the future.
+        # If you rely on this feature, please open a GitHub issue
+        # outlining your use-case to help us decide if it should be
+        # part of our public interface in the future.
+        _strict_response_validation: bool = False,
+    ) -> None:
+        self.aws_secret_key = aws_secret_key
+
+        self.aws_access_key = aws_access_key
+
+        if aws_region is None:
+            aws_region = os.environ.get("AWS_REGION") or "us-east-1"
+        self.aws_region = aws_region
+        self.aws_profile = aws_profile
+
+        self.aws_session_token = aws_session_token
+
+        if base_url is None:
+            base_url = os.environ.get("ANTHROPIC_BEDROCK_BASE_URL")
+        if base_url is None:
+            base_url = f"https://bedrock-runtime.{self.aws_region}.amazonaws.com"
+
+        super().__init__(
+            version=__version__,
+            base_url=base_url,
+            timeout=timeout,
+            max_retries=max_retries,
+            custom_headers=default_headers,
+            custom_query=default_query,
+            http_client=http_client,
+            _strict_response_validation=_strict_response_validation,
+        )
+
+        self.messages = AsyncMessages(self)
+        self.completions = AsyncCompletions(self)
+        self.beta = AsyncBeta(self)
+
+    @override
+    def _make_sse_decoder(self) -> AWSEventStreamDecoder:
+        return AWSEventStreamDecoder()
+
+    @override
+    async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
+        return _prepare_options(options)
+
+    @override
+    async def _prepare_request(self, request: httpx.Request) -> None:
+        from ._auth import get_auth_headers
+
+        data = request.read().decode()
+
+        headers = get_auth_headers(
+            method=request.method,
+            url=str(request.url),
+            headers=request.headers,
+            aws_access_key=self.aws_access_key,
+            aws_secret_key=self.aws_secret_key,
+            aws_session_token=self.aws_session_token,
+            region=self.aws_region or "us-east-1",
+            profile=self.aws_profile,
+            data=data,
+        )
+        request.headers.update(headers)
+
+    def copy(
+        self,
+        *,
+        aws_secret_key: str | None = None,
+        aws_access_key: str | None = None,
+        aws_region: str | None = None,
+        aws_session_token: str | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
+        http_client: httpx.AsyncClient | None = None,
+        max_retries: int | NotGiven = NOT_GIVEN,
+        default_headers: Mapping[str, str] | None = None,
+        set_default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        set_default_query: Mapping[str, object] | None = None,
+        _extra_kwargs: Mapping[str, Any] = {},
+    ) -> Self:
+        """
+        Create a new client instance re-using the same options given to the current client with optional overriding.
+        """
+        if default_headers is not None and set_default_headers is not None:
+            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")
+
+        if default_query is not None and set_default_query is not None:
+            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")
+
+        headers = self._custom_headers
+        if default_headers is not None:
+            headers = {**headers, **default_headers}
+        elif set_default_headers is not None:
+            headers = set_default_headers
+
+        params = self._custom_query
+        if default_query is not None:
+            params = {**params, **default_query}
+        elif set_default_query is not None:
+            params = set_default_query
+
+        return self.__class__(
+            aws_secret_key=aws_secret_key or self.aws_secret_key,
+            aws_access_key=aws_access_key or self.aws_access_key,
+            aws_region=aws_region or self.aws_region,
+            aws_session_token=aws_session_token or self.aws_session_token,
+            base_url=base_url or self.base_url,
+            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
+            http_client=http_client,
+            max_retries=max_retries if is_given(max_retries) else self.max_retries,
+            default_headers=headers,
+            default_query=params,
+            **_extra_kwargs,
+        )
+
+    # Alias for `copy` for nicer inline usage, e.g.
+    # client.with_options(timeout=10).foo.create(...)
+    with_options = copy
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream.py b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream.py
new file mode 100644
index 00000000..6512c468
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream.py
@@ -0,0 +1,37 @@
+from __future__ import annotations
+
+from typing import TypeVar
+
+import httpx
+
+from ..._client import Anthropic, AsyncAnthropic
+from ..._streaming import Stream, AsyncStream
+from ._stream_decoder import AWSEventStreamDecoder
+
+_T = TypeVar("_T")
+
+
+class BedrockStream(Stream[_T]):
+    def __init__(
+        self,
+        *,
+        cast_to: type[_T],
+        response: httpx.Response,
+        client: Anthropic,
+    ) -> None:
+        super().__init__(cast_to=cast_to, response=response, client=client)
+
+        self._decoder = AWSEventStreamDecoder()
+
+
+class AsyncBedrockStream(AsyncStream[_T]):
+    def __init__(
+        self,
+        *,
+        cast_to: type[_T],
+        response: httpx.Response,
+        client: AsyncAnthropic,
+    ) -> None:
+        super().__init__(cast_to=cast_to, response=response, client=client)
+
+        self._decoder = AWSEventStreamDecoder()
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream_decoder.py b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream_decoder.py
new file mode 100644
index 00000000..02e81a3c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/bedrock/_stream_decoder.py
@@ -0,0 +1,64 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Iterator, AsyncIterator
+
+from ..._utils import lru_cache
+from ..._streaming import ServerSentEvent
+
+if TYPE_CHECKING:
+    from botocore.model import Shape
+    from botocore.eventstream import EventStreamMessage
+
+
+@lru_cache(maxsize=None)
+def get_response_stream_shape() -> Shape:
+    from botocore.model import ServiceModel
+    from botocore.loaders import Loader
+
+    loader = Loader()
+    bedrock_service_dict = loader.load_service_model("bedrock-runtime", "service-2")
+    bedrock_service_model = ServiceModel(bedrock_service_dict)
+    return bedrock_service_model.shape_for("ResponseStream")
+
+
+class AWSEventStreamDecoder:
+    def __init__(self) -> None:
+        from botocore.parsers import EventStreamJSONParser
+
+        self.parser = EventStreamJSONParser()
+
+    def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]:
+        """Given an iterator that yields lines, iterate over it & yield every event encountered"""
+        from botocore.eventstream import EventStreamBuffer
+
+        event_stream_buffer = EventStreamBuffer()
+        for chunk in iterator:
+            event_stream_buffer.add_data(chunk)
+            for event in event_stream_buffer:
+                message = self._parse_message_from_event(event)
+                if message:
+                    yield ServerSentEvent(data=message, event="completion")
+
+    async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]:
+        """Given an async iterator that yields lines, iterate over it & yield every event encountered"""
+        from botocore.eventstream import EventStreamBuffer
+
+        event_stream_buffer = EventStreamBuffer()
+        async for chunk in iterator:
+            event_stream_buffer.add_data(chunk)
+            for event in event_stream_buffer:
+                message = self._parse_message_from_event(event)
+                if message:
+                    yield ServerSentEvent(data=message, event="completion")
+
+    def _parse_message_from_event(self, event: EventStreamMessage) -> str | None:
+        response_dict = event.to_response_dict()
+        parsed_response = self.parser.parse(response_dict, get_response_stream_shape())
+        if response_dict["status_code"] != 200:
+            raise ValueError(f"Bad response code, expected 200: {response_dict}")
+
+        chunk = parsed_response.get("chunk")
+        if not chunk:
+            return None
+
+        return chunk.get("bytes").decode()  # type: ignore[no-any-return]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/__init__.py
new file mode 100644
index 00000000..103fff58
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/__init__.py
@@ -0,0 +1,26 @@
+from ._types import (
+    TextEvent as TextEvent,
+    InputJsonEvent as InputJsonEvent,
+    MessageStopEvent as MessageStopEvent,
+    MessageStreamEvent as MessageStreamEvent,
+    ContentBlockStopEvent as ContentBlockStopEvent,
+)
+from ._messages import (
+    MessageStream as MessageStream,
+    AsyncMessageStream as AsyncMessageStream,
+    MessageStreamManager as MessageStreamManager,
+    AsyncMessageStreamManager as AsyncMessageStreamManager,
+)
+from ._beta_types import (
+    BetaTextEvent as BetaTextEvent,
+    BetaInputJsonEvent as BetaInputJsonEvent,
+    BetaMessageStopEvent as BetaMessageStopEvent,
+    BetaMessageStreamEvent as BetaMessageStreamEvent,
+    BetaContentBlockStopEvent as BetaContentBlockStopEvent,
+)
+from ._beta_messages import (
+    BetaMessageStream as BetaMessageStream,
+    BetaAsyncMessageStream as BetaAsyncMessageStream,
+    BetaMessageStreamManager as BetaMessageStreamManager,
+    BetaAsyncMessageStreamManager as BetaAsyncMessageStreamManager,
+)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_messages.py b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_messages.py
new file mode 100644
index 00000000..d979f83c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_messages.py
@@ -0,0 +1,462 @@
+from __future__ import annotations
+
+from types import TracebackType
+from typing import TYPE_CHECKING, Any, Type, Callable, cast
+from typing_extensions import Self, Iterator, Awaitable, AsyncIterator, assert_never
+
+import httpx
+from pydantic import BaseModel
+
+from ..._utils import consume_sync_iterator, consume_async_iterator
+from ..._models import build, construct_type, construct_type_unchecked
+from ._beta_types import (
+    BetaTextEvent,
+    BetaCitationEvent,
+    BetaThinkingEvent,
+    BetaInputJsonEvent,
+    BetaSignatureEvent,
+    BetaMessageStopEvent,
+    BetaMessageStreamEvent,
+    BetaContentBlockStopEvent,
+)
+from ..._streaming import Stream, AsyncStream
+from ...types.beta import BetaMessage, BetaContentBlock, BetaRawMessageStreamEvent
+
+
+class BetaMessageStream:
+    text_stream: Iterator[str]
+    """Iterator over just the text deltas in the stream.
+
+    ```py
+    for text in stream.text_stream:
+        print(text, end="", flush=True)
+    print()
+    ```
+    """
+
+    def __init__(self, raw_stream: Stream[BetaRawMessageStreamEvent]) -> None:
+        self._raw_stream = raw_stream
+        self.text_stream = self.__stream_text__()
+        self._iterator = self.__stream__()
+        self.__final_message_snapshot: BetaMessage | None = None
+
+    @property
+    def response(self) -> httpx.Response:
+        return self._raw_stream.response
+
+    @property
+    def request_id(self) -> str | None:
+        return self.response.headers.get("request-id")  # type: ignore[no-any-return]
+
+    def __next__(self) -> BetaMessageStreamEvent:
+        return self._iterator.__next__()
+
+    def __iter__(self) -> Iterator[BetaMessageStreamEvent]:
+        for item in self._iterator:
+            yield item
+
+    def __enter__(self) -> Self:
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.close()
+
+    def close(self) -> None:
+        """
+        Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        self._raw_stream.close()
+
+    def get_final_message(self) -> BetaMessage:
+        """Waits until the stream has been read to completion and returns
+        the accumulated `Message` object.
+        """
+        self.until_done()
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    def get_final_text(self) -> str:
+        """Returns all `text` content blocks concatenated together.
+
+        > [!NOTE]
+        > Currently the API will only respond with a single content block.
+
+        Will raise an error if no `text` content blocks were returned.
+        """
+        message = self.get_final_message()
+        text_blocks: list[str] = []
+        for block in message.content:
+            if block.type == "text":
+                text_blocks.append(block.text)
+
+        if not text_blocks:
+            raise RuntimeError("Expected to have received at least 1 text block")
+
+        return "".join(text_blocks)
+
+    def until_done(self) -> None:
+        """Blocks until the stream has been consumed"""
+        consume_sync_iterator(self)
+
+    # properties
+    @property
+    def current_message_snapshot(self) -> BetaMessage:
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    def __stream__(self) -> Iterator[BetaMessageStreamEvent]:
+        for sse_event in self._raw_stream:
+            self.__final_message_snapshot = accumulate_event(
+                event=sse_event,
+                current_snapshot=self.__final_message_snapshot,
+            )
+
+            events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
+            for event in events_to_fire:
+                yield event
+
+    def __stream_text__(self) -> Iterator[str]:
+        for chunk in self:
+            if chunk.type == "content_block_delta" and chunk.delta.type == "text_delta":
+                yield chunk.delta.text
+
+
+class BetaMessageStreamManager:
+    """Wrapper over MessageStream that is returned by `.stream()`.
+
+    ```py
+    with client.beta.messages.stream(...) as stream:
+        for chunk in stream:
+            ...
+    ```
+    """
+
+    def __init__(
+        self,
+        api_request: Callable[[], Stream[BetaRawMessageStreamEvent]],
+    ) -> None:
+        self.__stream: BetaMessageStream | None = None
+        self.__api_request = api_request
+
+    def __enter__(self) -> BetaMessageStream:
+        raw_stream = self.__api_request()
+        self.__stream = BetaMessageStream(raw_stream)
+        return self.__stream
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        if self.__stream is not None:
+            self.__stream.close()
+
+
+class BetaAsyncMessageStream:
+    text_stream: AsyncIterator[str]
+    """Async iterator over just the text deltas in the stream.
+
+    ```py
+    async for text in stream.text_stream:
+        print(text, end="", flush=True)
+    print()
+    ```
+    """
+
+    def __init__(self, raw_stream: AsyncStream[BetaRawMessageStreamEvent]) -> None:
+        self._raw_stream = raw_stream
+        self.text_stream = self.__stream_text__()
+        self._iterator = self.__stream__()
+        self.__final_message_snapshot: BetaMessage | None = None
+
+    @property
+    def response(self) -> httpx.Response:
+        return self._raw_stream.response
+
+    @property
+    def request_id(self) -> str | None:
+        return self.response.headers.get("request-id")  # type: ignore[no-any-return]
+
+    async def __anext__(self) -> BetaMessageStreamEvent:
+        return await self._iterator.__anext__()
+
+    async def __aiter__(self) -> AsyncIterator[BetaMessageStreamEvent]:
+        async for item in self._iterator:
+            yield item
+
+    async def __aenter__(self) -> Self:
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        await self.close()
+
+    async def close(self) -> None:
+        """
+        Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        await self._raw_stream.close()
+
+    async def get_final_message(self) -> BetaMessage:
+        """Waits until the stream has been read to completion and returns
+        the accumulated `Message` object.
+        """
+        await self.until_done()
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    async def get_final_text(self) -> str:
+        """Returns all `text` content blocks concatenated together.
+
+        > [!NOTE]
+        > Currently the API will only respond with a single content block.
+
+        Will raise an error if no `text` content blocks were returned.
+        """
+        message = await self.get_final_message()
+        text_blocks: list[str] = []
+        for block in message.content:
+            if block.type == "text":
+                text_blocks.append(block.text)
+
+        if not text_blocks:
+            raise RuntimeError("Expected to have received at least 1 text block")
+
+        return "".join(text_blocks)
+
+    async def until_done(self) -> None:
+        """Waits until the stream has been consumed"""
+        await consume_async_iterator(self)
+
+    # properties
+    @property
+    def current_message_snapshot(self) -> BetaMessage:
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    async def __stream__(self) -> AsyncIterator[BetaMessageStreamEvent]:
+        async for sse_event in self._raw_stream:
+            self.__final_message_snapshot = accumulate_event(
+                event=sse_event,
+                current_snapshot=self.__final_message_snapshot,
+            )
+
+            events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
+            for event in events_to_fire:
+                yield event
+
+    async def __stream_text__(self) -> AsyncIterator[str]:
+        async for chunk in self:
+            if chunk.type == "content_block_delta" and chunk.delta.type == "text_delta":
+                yield chunk.delta.text
+
+
+class BetaAsyncMessageStreamManager:
+    """Wrapper over BetaAsyncMessageStream that is returned by `.stream()`
+    so that an async context manager can be used without `await`ing the
+    original client call.
+
+    ```py
+    async with client.beta.messages.stream(...) as stream:
+        async for chunk in stream:
+            ...
+    ```
+    """
+
+    def __init__(
+        self,
+        api_request: Awaitable[AsyncStream[BetaRawMessageStreamEvent]],
+    ) -> None:
+        self.__stream: BetaAsyncMessageStream | None = None
+        self.__api_request = api_request
+
+    async def __aenter__(self) -> BetaAsyncMessageStream:
+        raw_stream = await self.__api_request
+        self.__stream = BetaAsyncMessageStream(raw_stream)
+        return self.__stream
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        if self.__stream is not None:
+            await self.__stream.close()
+
+
+def build_events(
+    *,
+    event: BetaRawMessageStreamEvent,
+    message_snapshot: BetaMessage,
+) -> list[BetaMessageStreamEvent]:
+    events_to_fire: list[BetaMessageStreamEvent] = []
+
+    if event.type == "message_start":
+        events_to_fire.append(event)
+    elif event.type == "message_delta":
+        events_to_fire.append(event)
+    elif event.type == "message_stop":
+        events_to_fire.append(build(BetaMessageStopEvent, type="message_stop", message=message_snapshot))
+    elif event.type == "content_block_start":
+        events_to_fire.append(event)
+    elif event.type == "content_block_delta":
+        events_to_fire.append(event)
+
+        content_block = message_snapshot.content[event.index]
+        if event.delta.type == "text_delta":
+            if content_block.type == "text":
+                events_to_fire.append(
+                    build(
+                        BetaTextEvent,
+                        type="text",
+                        text=event.delta.text,
+                        snapshot=content_block.text,
+                    )
+                )
+        elif event.delta.type == "input_json_delta":
+            if content_block.type == "tool_use":
+                events_to_fire.append(
+                    build(
+                        BetaInputJsonEvent,
+                        type="input_json",
+                        partial_json=event.delta.partial_json,
+                        snapshot=content_block.input,
+                    )
+                )
+        elif event.delta.type == "citations_delta":
+            if content_block.type == "text":
+                events_to_fire.append(
+                    build(
+                        BetaCitationEvent,
+                        type="citation",
+                        citation=event.delta.citation,
+                        snapshot=content_block.citations or [],
+                    )
+                )
+        elif event.delta.type == "thinking_delta":
+            if content_block.type == "thinking":
+                events_to_fire.append(
+                    build(
+                        BetaThinkingEvent,
+                        type="thinking",
+                        thinking=event.delta.thinking,
+                        snapshot=content_block.thinking,
+                    )
+                )
+        elif event.delta.type == "signature_delta":
+            if content_block.type == "thinking":
+                events_to_fire.append(
+                    build(
+                        BetaSignatureEvent,
+                        type="signature",
+                        signature=content_block.signature,
+                    )
+                )
+            pass
+        else:
+            # we only want exhaustive checking for linters, not at runtime
+            if TYPE_CHECKING:  # type: ignore[unreachable]
+                assert_never(event.delta)
+    elif event.type == "content_block_stop":
+        content_block = message_snapshot.content[event.index]
+
+        events_to_fire.append(
+            build(BetaContentBlockStopEvent, type="content_block_stop", index=event.index, content_block=content_block),
+        )
+    else:
+        # we only want exhaustive checking for linters, not at runtime
+        if TYPE_CHECKING:  # type: ignore[unreachable]
+            assert_never(event)
+
+    return events_to_fire
+
+
+JSON_BUF_PROPERTY = "__json_buf"
+
+
+def accumulate_event(
+    *,
+    event: BetaRawMessageStreamEvent,
+    current_snapshot: BetaMessage | None,
+) -> BetaMessage:
+    if not isinstance(cast(Any, event), BaseModel):
+        event = cast(  # pyright: ignore[reportUnnecessaryCast]
+            BetaRawMessageStreamEvent,
+            construct_type_unchecked(
+                type_=cast(Type[BetaRawMessageStreamEvent], BetaRawMessageStreamEvent),
+                value=event,
+            ),
+        )
+        if not isinstance(cast(Any, event), BaseModel):
+            raise TypeError(f"Unexpected event runtime type, after deserialising twice - {event} - {type(event)}")
+
+    if current_snapshot is None:
+        if event.type == "message_start":
+            return BetaMessage.construct(**cast(Any, event.message.to_dict()))
+
+        raise RuntimeError(f'Unexpected event order, got {event.type} before "message_start"')
+
+    if event.type == "content_block_start":
+        # TODO: check index
+        current_snapshot.content.append(
+            cast(
+                BetaContentBlock,
+                construct_type(type_=BetaContentBlock, value=event.content_block.model_dump()),
+            ),
+        )
+    elif event.type == "content_block_delta":
+        content = current_snapshot.content[event.index]
+        if event.delta.type == "text_delta":
+            if content.type == "text":
+                content.text += event.delta.text
+        elif event.delta.type == "input_json_delta":
+            if content.type == "tool_use":
+                from jiter import from_json
+
+                # we need to keep track of the raw JSON string as well so that we can
+                # re-parse it for each delta, for now we just store it as an untyped
+                # property on the snapshot
+                json_buf = cast(bytes, getattr(content, JSON_BUF_PROPERTY, b""))
+                json_buf += bytes(event.delta.partial_json, "utf-8")
+
+                if json_buf:
+                    content.input = from_json(json_buf, partial_mode=True)
+
+                setattr(content, JSON_BUF_PROPERTY, json_buf)
+        elif event.delta.type == "citations_delta":
+            if content.type == "text":
+                if not content.citations:
+                    content.citations = [event.delta.citation]
+                else:
+                    content.citations.append(event.delta.citation)
+        elif event.delta.type == "thinking_delta":
+            if content.type == "thinking":
+                content.thinking += event.delta.thinking
+        elif event.delta.type == "signature_delta":
+            if content.type == "thinking":
+                content.signature = event.delta.signature
+        else:
+            # we only want exhaustive checking for linters, not at runtime
+            if TYPE_CHECKING:  # type: ignore[unreachable]
+                assert_never(event.delta)
+    elif event.type == "message_delta":
+        current_snapshot.stop_reason = event.delta.stop_reason
+        current_snapshot.stop_sequence = event.delta.stop_sequence
+        current_snapshot.usage.output_tokens = event.usage.output_tokens
+
+    return current_snapshot
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_types.py b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_types.py
new file mode 100644
index 00000000..24bb710c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_beta_types.py
@@ -0,0 +1,100 @@
+from typing import Union
+from typing_extensions import List, Literal, Annotated
+
+from ..._models import BaseModel
+from ...types.beta import (
+    BetaMessage,
+    BetaContentBlock,
+    BetaRawMessageStopEvent,
+    BetaRawMessageDeltaEvent,
+    BetaRawMessageStartEvent,
+    BetaRawContentBlockStopEvent,
+    BetaRawContentBlockDeltaEvent,
+    BetaRawContentBlockStartEvent,
+)
+from ..._utils._transform import PropertyInfo
+from ...types.beta.beta_citations_delta import Citation
+
+
+class BetaTextEvent(BaseModel):
+    type: Literal["text"]
+
+    text: str
+    """The text delta"""
+
+    snapshot: str
+    """The entire accumulated text"""
+
+
+class BetaCitationEvent(BaseModel):
+    type: Literal["citation"]
+
+    citation: Citation
+    """The new citation"""
+
+    snapshot: List[Citation]
+    """All of the accumulated citations"""
+
+
+class BetaThinkingEvent(BaseModel):
+    type: Literal["thinking"]
+
+    thinking: str
+    """The thinking delta"""
+
+    snapshot: str
+    """The accumulated thinking so far"""
+
+
+class BetaSignatureEvent(BaseModel):
+    type: Literal["signature"]
+
+    signature: str
+    """The signature of the thinking block"""
+
+
+class BetaInputJsonEvent(BaseModel):
+    type: Literal["input_json"]
+
+    partial_json: str
+    """A partial JSON string delta
+
+    e.g. `'"San Francisco,'`
+    """
+
+    snapshot: object
+    """The currently accumulated parsed object.
+
+
+    e.g. `{'location': 'San Francisco, CA'}`
+    """
+
+
+class BetaMessageStopEvent(BetaRawMessageStopEvent):
+    type: Literal["message_stop"]
+
+    message: BetaMessage
+
+
+class BetaContentBlockStopEvent(BetaRawContentBlockStopEvent):
+    type: Literal["content_block_stop"]
+
+    content_block: BetaContentBlock
+
+
+BetaMessageStreamEvent = Annotated[
+    Union[
+        BetaTextEvent,
+        BetaCitationEvent,
+        BetaThinkingEvent,
+        BetaSignatureEvent,
+        BetaInputJsonEvent,
+        BetaRawMessageStartEvent,
+        BetaRawMessageDeltaEvent,
+        BetaMessageStopEvent,
+        BetaRawContentBlockStartEvent,
+        BetaRawContentBlockDeltaEvent,
+        BetaContentBlockStopEvent,
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_messages.py b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_messages.py
new file mode 100644
index 00000000..09ed24f9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_messages.py
@@ -0,0 +1,462 @@
+from __future__ import annotations
+
+from types import TracebackType
+from typing import TYPE_CHECKING, Any, Type, Callable, cast
+from typing_extensions import Self, Iterator, Awaitable, AsyncIterator, assert_never
+
+import httpx
+from pydantic import BaseModel
+
+from ._types import (
+    TextEvent,
+    CitationEvent,
+    ThinkingEvent,
+    InputJsonEvent,
+    SignatureEvent,
+    MessageStopEvent,
+    MessageStreamEvent,
+    ContentBlockStopEvent,
+)
+from ...types import Message, ContentBlock, RawMessageStreamEvent
+from ..._utils import consume_sync_iterator, consume_async_iterator
+from ..._models import build, construct_type, construct_type_unchecked
+from ..._streaming import Stream, AsyncStream
+
+
+class MessageStream:
+    text_stream: Iterator[str]
+    """Iterator over just the text deltas in the stream.
+
+    ```py
+    for text in stream.text_stream:
+        print(text, end="", flush=True)
+    print()
+    ```
+    """
+
+    def __init__(self, raw_stream: Stream[RawMessageStreamEvent]) -> None:
+        self._raw_stream = raw_stream
+        self.text_stream = self.__stream_text__()
+        self._iterator = self.__stream__()
+        self.__final_message_snapshot: Message | None = None
+
+    @property
+    def response(self) -> httpx.Response:
+        return self._raw_stream.response
+
+    @property
+    def request_id(self) -> str | None:
+        return self.response.headers.get("request-id")  # type: ignore[no-any-return]
+
+    def __next__(self) -> MessageStreamEvent:
+        return self._iterator.__next__()
+
+    def __iter__(self) -> Iterator[MessageStreamEvent]:
+        for item in self._iterator:
+            yield item
+
+    def __enter__(self) -> Self:
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.close()
+
+    def close(self) -> None:
+        """
+        Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        self._raw_stream.close()
+
+    def get_final_message(self) -> Message:
+        """Waits until the stream has been read to completion and returns
+        the accumulated `Message` object.
+        """
+        self.until_done()
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    def get_final_text(self) -> str:
+        """Returns all `text` content blocks concatenated together.
+
+        > [!NOTE]
+        > Currently the API will only respond with a single content block.
+
+        Will raise an error if no `text` content blocks were returned.
+        """
+        message = self.get_final_message()
+        text_blocks: list[str] = []
+        for block in message.content:
+            if block.type == "text":
+                text_blocks.append(block.text)
+
+        if not text_blocks:
+            raise RuntimeError("Expected to have received at least 1 text block")
+
+        return "".join(text_blocks)
+
+    def until_done(self) -> None:
+        """Blocks until the stream has been consumed"""
+        consume_sync_iterator(self)
+
+    # properties
+    @property
+    def current_message_snapshot(self) -> Message:
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    def __stream__(self) -> Iterator[MessageStreamEvent]:
+        for sse_event in self._raw_stream:
+            self.__final_message_snapshot = accumulate_event(
+                event=sse_event,
+                current_snapshot=self.__final_message_snapshot,
+            )
+
+            events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
+            for event in events_to_fire:
+                yield event
+
+    def __stream_text__(self) -> Iterator[str]:
+        for chunk in self:
+            if chunk.type == "content_block_delta" and chunk.delta.type == "text_delta":
+                yield chunk.delta.text
+
+
+class MessageStreamManager:
+    """Wrapper over MessageStream that is returned by `.stream()`.
+
+    ```py
+    with client.messages.stream(...) as stream:
+        for chunk in stream:
+            ...
+    ```
+    """
+
+    def __init__(
+        self,
+        api_request: Callable[[], Stream[RawMessageStreamEvent]],
+    ) -> None:
+        self.__stream: MessageStream | None = None
+        self.__api_request = api_request
+
+    def __enter__(self) -> MessageStream:
+        raw_stream = self.__api_request()
+        self.__stream = MessageStream(raw_stream)
+        return self.__stream
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        if self.__stream is not None:
+            self.__stream.close()
+
+
+class AsyncMessageStream:
+    text_stream: AsyncIterator[str]
+    """Async iterator over just the text deltas in the stream.
+
+    ```py
+    async for text in stream.text_stream:
+        print(text, end="", flush=True)
+    print()
+    ```
+    """
+
+    def __init__(self, raw_stream: AsyncStream[RawMessageStreamEvent]) -> None:
+        self._raw_stream = raw_stream
+        self.text_stream = self.__stream_text__()
+        self._iterator = self.__stream__()
+        self.__final_message_snapshot: Message | None = None
+
+    @property
+    def response(self) -> httpx.Response:
+        return self._raw_stream.response
+
+    @property
+    def request_id(self) -> str | None:
+        return self.response.headers.get("request-id")  # type: ignore[no-any-return]
+
+    async def __anext__(self) -> MessageStreamEvent:
+        return await self._iterator.__anext__()
+
+    async def __aiter__(self) -> AsyncIterator[MessageStreamEvent]:
+        async for item in self._iterator:
+            yield item
+
+    async def __aenter__(self) -> Self:
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        await self.close()
+
+    async def close(self) -> None:
+        """
+        Close the response and release the connection.
+
+        Automatically called if the response body is read to completion.
+        """
+        await self._raw_stream.close()
+
+    async def get_final_message(self) -> Message:
+        """Waits until the stream has been read to completion and returns
+        the accumulated `Message` object.
+        """
+        await self.until_done()
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    async def get_final_text(self) -> str:
+        """Returns all `text` content blocks concatenated together.
+
+        > [!NOTE]
+        > Currently the API will only respond with a single content block.
+
+        Will raise an error if no `text` content blocks were returned.
+        """
+        message = await self.get_final_message()
+        text_blocks: list[str] = []
+        for block in message.content:
+            if block.type == "text":
+                text_blocks.append(block.text)
+
+        if not text_blocks:
+            raise RuntimeError("Expected to have received at least 1 text block")
+
+        return "".join(text_blocks)
+
+    async def until_done(self) -> None:
+        """Waits until the stream has been consumed"""
+        await consume_async_iterator(self)
+
+    # properties
+    @property
+    def current_message_snapshot(self) -> Message:
+        assert self.__final_message_snapshot is not None
+        return self.__final_message_snapshot
+
+    async def __stream__(self) -> AsyncIterator[MessageStreamEvent]:
+        async for sse_event in self._raw_stream:
+            self.__final_message_snapshot = accumulate_event(
+                event=sse_event,
+                current_snapshot=self.__final_message_snapshot,
+            )
+
+            events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
+            for event in events_to_fire:
+                yield event
+
+    async def __stream_text__(self) -> AsyncIterator[str]:
+        async for chunk in self:
+            if chunk.type == "content_block_delta" and chunk.delta.type == "text_delta":
+                yield chunk.delta.text
+
+
+class AsyncMessageStreamManager:
+    """Wrapper over AsyncMessageStream that is returned by `.stream()`
+    so that an async context manager can be used without `await`ing the
+    original client call.
+
+    ```py
+    async with client.messages.stream(...) as stream:
+        async for chunk in stream:
+            ...
+    ```
+    """
+
+    def __init__(
+        self,
+        api_request: Awaitable[AsyncStream[RawMessageStreamEvent]],
+    ) -> None:
+        self.__stream: AsyncMessageStream | None = None
+        self.__api_request = api_request
+
+    async def __aenter__(self) -> AsyncMessageStream:
+        raw_stream = await self.__api_request
+        self.__stream = AsyncMessageStream(raw_stream)
+        return self.__stream
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        if self.__stream is not None:
+            await self.__stream.close()
+
+
+def build_events(
+    *,
+    event: RawMessageStreamEvent,
+    message_snapshot: Message,
+) -> list[MessageStreamEvent]:
+    events_to_fire: list[MessageStreamEvent] = []
+
+    if event.type == "message_start":
+        events_to_fire.append(event)
+    elif event.type == "message_delta":
+        events_to_fire.append(event)
+    elif event.type == "message_stop":
+        events_to_fire.append(build(MessageStopEvent, type="message_stop", message=message_snapshot))
+    elif event.type == "content_block_start":
+        events_to_fire.append(event)
+    elif event.type == "content_block_delta":
+        events_to_fire.append(event)
+
+        content_block = message_snapshot.content[event.index]
+        if event.delta.type == "text_delta":
+            if content_block.type == "text":
+                events_to_fire.append(
+                    build(
+                        TextEvent,
+                        type="text",
+                        text=event.delta.text,
+                        snapshot=content_block.text,
+                    )
+                )
+        elif event.delta.type == "input_json_delta":
+            if content_block.type == "tool_use":
+                events_to_fire.append(
+                    build(
+                        InputJsonEvent,
+                        type="input_json",
+                        partial_json=event.delta.partial_json,
+                        snapshot=content_block.input,
+                    )
+                )
+        elif event.delta.type == "citations_delta":
+            if content_block.type == "text":
+                events_to_fire.append(
+                    build(
+                        CitationEvent,
+                        type="citation",
+                        citation=event.delta.citation,
+                        snapshot=content_block.citations or [],
+                    )
+                )
+        elif event.delta.type == "thinking_delta":
+            if content_block.type == "thinking":
+                events_to_fire.append(
+                    build(
+                        ThinkingEvent,
+                        type="thinking",
+                        thinking=event.delta.thinking,
+                        snapshot=content_block.thinking,
+                    )
+                )
+        elif event.delta.type == "signature_delta":
+            if content_block.type == "thinking":
+                events_to_fire.append(
+                    build(
+                        SignatureEvent,
+                        type="signature",
+                        signature=content_block.signature,
+                    )
+                )
+            pass
+        else:
+            # we only want exhaustive checking for linters, not at runtime
+            if TYPE_CHECKING:  # type: ignore[unreachable]
+                assert_never(event.delta)
+    elif event.type == "content_block_stop":
+        content_block = message_snapshot.content[event.index]
+
+        events_to_fire.append(
+            build(ContentBlockStopEvent, type="content_block_stop", index=event.index, content_block=content_block),
+        )
+    else:
+        # we only want exhaustive checking for linters, not at runtime
+        if TYPE_CHECKING:  # type: ignore[unreachable]
+            assert_never(event)
+
+    return events_to_fire
+
+
+JSON_BUF_PROPERTY = "__json_buf"
+
+
+def accumulate_event(
+    *,
+    event: RawMessageStreamEvent,
+    current_snapshot: Message | None,
+) -> Message:
+    if not isinstance(cast(Any, event), BaseModel):
+        event = cast(  # pyright: ignore[reportUnnecessaryCast]
+            RawMessageStreamEvent,
+            construct_type_unchecked(
+                type_=cast(Type[RawMessageStreamEvent], RawMessageStreamEvent),
+                value=event,
+            ),
+        )
+        if not isinstance(cast(Any, event), BaseModel):
+            raise TypeError(f"Unexpected event runtime type, after deserialising twice - {event} - {type(event)}")
+
+    if current_snapshot is None:
+        if event.type == "message_start":
+            return Message.construct(**cast(Any, event.message.to_dict()))
+
+        raise RuntimeError(f'Unexpected event order, got {event.type} before "message_start"')
+
+    if event.type == "content_block_start":
+        # TODO: check index
+        current_snapshot.content.append(
+            cast(
+                ContentBlock,
+                construct_type(type_=ContentBlock, value=event.content_block.model_dump()),
+            ),
+        )
+    elif event.type == "content_block_delta":
+        content = current_snapshot.content[event.index]
+        if event.delta.type == "text_delta":
+            if content.type == "text":
+                content.text += event.delta.text
+        elif event.delta.type == "input_json_delta":
+            if content.type == "tool_use":
+                from jiter import from_json
+
+                # we need to keep track of the raw JSON string as well so that we can
+                # re-parse it for each delta, for now we just store it as an untyped
+                # property on the snapshot
+                json_buf = cast(bytes, getattr(content, JSON_BUF_PROPERTY, b""))
+                json_buf += bytes(event.delta.partial_json, "utf-8")
+
+                if json_buf:
+                    content.input = from_json(json_buf, partial_mode=True)
+
+                setattr(content, JSON_BUF_PROPERTY, json_buf)
+        elif event.delta.type == "citations_delta":
+            if content.type == "text":
+                if not content.citations:
+                    content.citations = [event.delta.citation]
+                else:
+                    content.citations.append(event.delta.citation)
+        elif event.delta.type == "thinking_delta":
+            if content.type == "thinking":
+                content.thinking += event.delta.thinking
+        elif event.delta.type == "signature_delta":
+            if content.type == "thinking":
+                content.signature = event.delta.signature
+        else:
+            # we only want exhaustive checking for linters, not at runtime
+            if TYPE_CHECKING:  # type: ignore[unreachable]
+                assert_never(event.delta)
+    elif event.type == "message_delta":
+        current_snapshot.stop_reason = event.delta.stop_reason
+        current_snapshot.stop_sequence = event.delta.stop_sequence
+        current_snapshot.usage.output_tokens = event.usage.output_tokens
+
+    return current_snapshot
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_types.py b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_types.py
new file mode 100644
index 00000000..0918427a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/streaming/_types.py
@@ -0,0 +1,100 @@
+from typing import Union
+from typing_extensions import List, Literal, Annotated
+
+from ...types import (
+    Message,
+    ContentBlock,
+    MessageDeltaEvent as RawMessageDeltaEvent,
+    MessageStartEvent as RawMessageStartEvent,
+    RawMessageStopEvent,
+    ContentBlockDeltaEvent as RawContentBlockDeltaEvent,
+    ContentBlockStartEvent as RawContentBlockStartEvent,
+    RawContentBlockStopEvent,
+)
+from ..._models import BaseModel
+from ..._utils._transform import PropertyInfo
+from ...types.citations_delta import Citation
+
+
+class TextEvent(BaseModel):
+    type: Literal["text"]
+
+    text: str
+    """The text delta"""
+
+    snapshot: str
+    """The entire accumulated text"""
+
+
+class CitationEvent(BaseModel):
+    type: Literal["citation"]
+
+    citation: Citation
+    """The new citation"""
+
+    snapshot: List[Citation]
+    """All of the accumulated citations"""
+
+
+class ThinkingEvent(BaseModel):
+    type: Literal["thinking"]
+
+    thinking: str
+    """The thinking delta"""
+
+    snapshot: str
+    """The accumulated thinking so far"""
+
+
+class SignatureEvent(BaseModel):
+    type: Literal["signature"]
+
+    signature: str
+    """The signature of the thinking block"""
+
+
+class InputJsonEvent(BaseModel):
+    type: Literal["input_json"]
+
+    partial_json: str
+    """A partial JSON string delta
+
+    e.g. `'"San Francisco,'`
+    """
+
+    snapshot: object
+    """The currently accumulated parsed object.
+
+
+    e.g. `{'location': 'San Francisco, CA'}`
+    """
+
+
+class MessageStopEvent(RawMessageStopEvent):
+    type: Literal["message_stop"]
+
+    message: Message
+
+
+class ContentBlockStopEvent(RawContentBlockStopEvent):
+    type: Literal["content_block_stop"]
+
+    content_block: ContentBlock
+
+
+MessageStreamEvent = Annotated[
+    Union[
+        TextEvent,
+        CitationEvent,
+        ThinkingEvent,
+        SignatureEvent,
+        InputJsonEvent,
+        RawMessageStartEvent,
+        RawMessageDeltaEvent,
+        MessageStopEvent,
+        RawContentBlockStartEvent,
+        RawContentBlockDeltaEvent,
+        ContentBlockStopEvent,
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/__init__.py
new file mode 100644
index 00000000..45b6301e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/__init__.py
@@ -0,0 +1 @@
+from ._client import AnthropicVertex as AnthropicVertex, AsyncAnthropicVertex as AsyncAnthropicVertex
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_auth.py b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_auth.py
new file mode 100644
index 00000000..3063016a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_auth.py
@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, cast
+
+from .._extras import google_auth
+
+if TYPE_CHECKING:
+    from google.auth.credentials import Credentials  # type: ignore[import-untyped]
+
+# pyright: reportMissingTypeStubs=false, reportUnknownVariableType=false, reportUnknownMemberType=false, reportUnknownArgumentType=false
+# google libraries don't provide types :/
+
+# Note: these functions are blocking as they make HTTP requests, the async
+# client runs these functions in a separate thread to ensure they do not
+# cause synchronous blocking issues.
+
+
+def load_auth(*, project_id: str | None) -> tuple[Credentials, str]:
+    from google.auth.transport.requests import Request  # type: ignore[import-untyped]
+
+    credentials, loaded_project_id = google_auth.default(
+        scopes=["https://www.googleapis.com/auth/cloud-platform"],
+    )
+    credentials = cast(Any, credentials)
+    credentials.refresh(Request())
+
+    if not project_id:
+        project_id = loaded_project_id
+
+    if not project_id:
+        raise ValueError("Could not resolve project_id")
+
+    if not isinstance(project_id, str):
+        raise TypeError(f"Expected project_id to be a str but got {type(project_id)}")
+
+    return credentials, project_id
+
+
+def refresh_auth(credentials: Credentials) -> None:
+    from google.auth.transport.requests import Request  # type: ignore[import-untyped]
+
+    credentials.refresh(Request())
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta.py b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta.py
new file mode 100644
index 00000000..f2a91b42
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta.py
@@ -0,0 +1,102 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ._beta_messages import (
+    Messages,
+    AsyncMessages,
+    MessagesWithRawResponse,
+    AsyncMessagesWithRawResponse,
+    MessagesWithStreamingResponse,
+    AsyncMessagesWithStreamingResponse,
+)
+
+__all__ = ["Beta", "AsyncBeta"]
+
+
+class Beta(SyncAPIResource):
+    @cached_property
+    def messages(self) -> Messages:
+        return Messages(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> BetaWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return BetaWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> BetaWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return BetaWithStreamingResponse(self)
+
+
+class AsyncBeta(AsyncAPIResource):
+    @cached_property
+    def messages(self) -> AsyncMessages:
+        return AsyncMessages(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> AsyncBetaWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncBetaWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncBetaWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncBetaWithStreamingResponse(self)
+
+
+class BetaWithRawResponse:
+    def __init__(self, beta: Beta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> MessagesWithRawResponse:
+        return MessagesWithRawResponse(self._beta.messages)
+
+
+class AsyncBetaWithRawResponse:
+    def __init__(self, beta: AsyncBeta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> AsyncMessagesWithRawResponse:
+        return AsyncMessagesWithRawResponse(self._beta.messages)
+
+
+class BetaWithStreamingResponse:
+    def __init__(self, beta: Beta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> MessagesWithStreamingResponse:
+        return MessagesWithStreamingResponse(self._beta.messages)
+
+
+class AsyncBetaWithStreamingResponse:
+    def __init__(self, beta: AsyncBeta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def messages(self) -> AsyncMessagesWithStreamingResponse:
+        return AsyncMessagesWithStreamingResponse(self._beta.messages)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta_messages.py b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta_messages.py
new file mode 100644
index 00000000..332f6fba
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_beta_messages.py
@@ -0,0 +1,93 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ... import _legacy_response
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...resources.beta import Messages as FirstPartyMessagesAPI, AsyncMessages as FirstPartyAsyncMessagesAPI
+
+__all__ = ["Messages", "AsyncMessages"]
+
+
+class Messages(SyncAPIResource):
+    create = FirstPartyMessagesAPI.create
+
+    @cached_property
+    def with_raw_response(self) -> MessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return MessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> MessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return MessagesWithStreamingResponse(self)
+
+
+class AsyncMessages(AsyncAPIResource):
+    create = FirstPartyAsyncMessagesAPI.create
+
+    @cached_property
+    def with_raw_response(self) -> AsyncMessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return the
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncMessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncMessagesWithStreamingResponse(self)
+
+
+class MessagesWithRawResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.to_raw_response_wrapper(
+            messages.create,
+        )
+
+
+class AsyncMessagesWithRawResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.async_to_raw_response_wrapper(
+            messages.create,
+        )
+
+
+class MessagesWithStreamingResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = to_streamed_response_wrapper(
+            messages.create,
+        )
+
+
+class AsyncMessagesWithStreamingResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = async_to_streamed_response_wrapper(
+            messages.create,
+        )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_client.py b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_client.py
new file mode 100644
index 00000000..c5ee9909
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/lib/vertex/_client.py
@@ -0,0 +1,406 @@
+from __future__ import annotations
+
+import os
+from typing import TYPE_CHECKING, Any, Union, Mapping, TypeVar
+from typing_extensions import Self, override
+
+import httpx
+
+from ... import _exceptions
+from ._auth import load_auth, refresh_auth
+from ._beta import Beta, AsyncBeta
+from ..._types import NOT_GIVEN, NotGiven
+from ..._utils import is_dict, asyncify, is_given
+from ..._compat import model_copy, typed_cached_property
+from ..._models import FinalRequestOptions
+from ..._version import __version__
+from ..._streaming import Stream, AsyncStream
+from ..._exceptions import AnthropicError, APIStatusError
+from ..._base_client import (
+    DEFAULT_MAX_RETRIES,
+    BaseClient,
+    SyncAPIClient,
+    AsyncAPIClient,
+)
+from ...resources.messages import Messages, AsyncMessages
+
+if TYPE_CHECKING:
+    from google.auth.credentials import Credentials as GoogleCredentials  # type: ignore
+
+
+DEFAULT_VERSION = "vertex-2023-10-16"
+
+_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient])
+_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]])
+
+
+class BaseVertexClient(BaseClient[_HttpxClientT, _DefaultStreamT]):
+    @typed_cached_property
+    def region(self) -> str:
+        raise RuntimeError("region not set")
+
+    @typed_cached_property
+    def project_id(self) -> str | None:
+        project_id = os.environ.get("ANTHROPIC_VERTEX_PROJECT_ID")
+        if project_id:
+            return project_id
+
+        return None
+
+    @override
+    def _make_status_error(
+        self,
+        err_msg: str,
+        *,
+        body: object,
+        response: httpx.Response,
+    ) -> APIStatusError:
+        if response.status_code == 400:
+            return _exceptions.BadRequestError(err_msg, response=response, body=body)
+
+        if response.status_code == 401:
+            return _exceptions.AuthenticationError(err_msg, response=response, body=body)
+
+        if response.status_code == 403:
+            return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)
+
+        if response.status_code == 404:
+            return _exceptions.NotFoundError(err_msg, response=response, body=body)
+
+        if response.status_code == 409:
+            return _exceptions.ConflictError(err_msg, response=response, body=body)
+
+        if response.status_code == 422:
+            return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)
+
+        if response.status_code == 429:
+            return _exceptions.RateLimitError(err_msg, response=response, body=body)
+
+        if response.status_code == 503:
+            return _exceptions.ServiceUnavailableError(err_msg, response=response, body=body)
+
+        if response.status_code == 504:
+            return _exceptions.DeadlineExceededError(err_msg, response=response, body=body)
+
+        if response.status_code >= 500:
+            return _exceptions.InternalServerError(err_msg, response=response, body=body)
+        return APIStatusError(err_msg, response=response, body=body)
+
+
+class AnthropicVertex(BaseVertexClient[httpx.Client, Stream[Any]], SyncAPIClient):
+    messages: Messages
+    beta: Beta
+
+    def __init__(
+        self,
+        *,
+        region: str | NotGiven = NOT_GIVEN,
+        project_id: str | NotGiven = NOT_GIVEN,
+        access_token: str | None = None,
+        credentials: GoogleCredentials | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        # Configure a custom httpx client. See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
+        http_client: httpx.Client | None = None,
+        _strict_response_validation: bool = False,
+    ) -> None:
+        if not is_given(region):
+            region = os.environ.get("CLOUD_ML_REGION", NOT_GIVEN)
+        if not is_given(region):
+            raise ValueError(
+                "No region was given. The client should be instantiated with the `region` argument or the `CLOUD_ML_REGION` environment variable should be set."
+            )
+
+        if base_url is None:
+            base_url = os.environ.get("ANTHROPIC_VERTEX_BASE_URL")
+            if base_url is None:
+                base_url = f"https://{region}-aiplatform.googleapis.com/v1"
+
+        super().__init__(
+            version=__version__,
+            base_url=base_url,
+            timeout=timeout,
+            max_retries=max_retries,
+            custom_headers=default_headers,
+            custom_query=default_query,
+            http_client=http_client,
+            _strict_response_validation=_strict_response_validation,
+        )
+
+        if is_given(project_id):
+            self.project_id = project_id
+
+        self.region = region
+        self.access_token = access_token
+        self.credentials = credentials
+
+        self.messages = Messages(self)
+        self.beta = Beta(self)
+
+    @override
+    def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
+        return _prepare_options(options, project_id=self.project_id, region=self.region)
+
+    @override
+    def _prepare_request(self, request: httpx.Request) -> None:
+        if request.headers.get("Authorization"):
+            # already authenticated, nothing for us to do
+            return
+
+        request.headers["Authorization"] = f"Bearer {self._ensure_access_token()}"
+
+    def _ensure_access_token(self) -> str:
+        if self.access_token is not None:
+            return self.access_token
+
+        if not self.credentials:
+            self.credentials, project_id = load_auth(project_id=self.project_id)
+            if not self.project_id:
+                self.project_id = project_id
+
+        if self.credentials.expired or not self.credentials.token:
+            refresh_auth(self.credentials)
+
+        if not self.credentials.token:
+            raise RuntimeError("Could not resolve API token from the environment")
+
+        assert isinstance(self.credentials.token, str)
+        return self.credentials.token
+
+    def copy(
+        self,
+        *,
+        region: str | NotGiven = NOT_GIVEN,
+        project_id: str | NotGiven = NOT_GIVEN,
+        access_token: str | None = None,
+        credentials: GoogleCredentials | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+        http_client: httpx.Client | None = None,
+        max_retries: int | NotGiven = NOT_GIVEN,
+        default_headers: Mapping[str, str] | None = None,
+        set_default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        set_default_query: Mapping[str, object] | None = None,
+        _extra_kwargs: Mapping[str, Any] = {},
+    ) -> Self:
+        """
+        Create a new client instance re-using the same options given to the current client with optional overriding.
+        """
+        if default_headers is not None and set_default_headers is not None:
+            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")
+
+        if default_query is not None and set_default_query is not None:
+            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")
+
+        headers = self._custom_headers
+        if default_headers is not None:
+            headers = {**headers, **default_headers}
+        elif set_default_headers is not None:
+            headers = set_default_headers
+
+        params = self._custom_query
+        if default_query is not None:
+            params = {**params, **default_query}
+        elif set_default_query is not None:
+            params = set_default_query
+
+        http_client = http_client or self._client
+
+        return self.__class__(
+            region=region if is_given(region) else self.region,
+            project_id=project_id if is_given(project_id) else self.project_id or NOT_GIVEN,
+            access_token=access_token or self.access_token,
+            credentials=credentials or self.credentials,
+            base_url=base_url or self.base_url,
+            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
+            http_client=http_client,
+            max_retries=max_retries if is_given(max_retries) else self.max_retries,
+            default_headers=headers,
+            default_query=params,
+            **_extra_kwargs,
+        )
+
+    # Alias for `copy` for nicer inline usage, e.g.
+    # client.with_options(timeout=10).foo.create(...)
+    with_options = copy
+
+
+class AsyncAnthropicVertex(BaseVertexClient[httpx.AsyncClient, AsyncStream[Any]], AsyncAPIClient):
+    messages: AsyncMessages
+    beta: AsyncBeta
+
+    def __init__(
+        self,
+        *,
+        region: str | NotGiven = NOT_GIVEN,
+        project_id: str | NotGiven = NOT_GIVEN,
+        access_token: str | None = None,
+        credentials: GoogleCredentials | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+        max_retries: int = DEFAULT_MAX_RETRIES,
+        default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        # Configure a custom httpx client. See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
+        http_client: httpx.AsyncClient | None = None,
+        _strict_response_validation: bool = False,
+    ) -> None:
+        if not is_given(region):
+            region = os.environ.get("CLOUD_ML_REGION", NOT_GIVEN)
+        if not is_given(region):
+            raise ValueError(
+                "No region was given. The client should be instantiated with the `region` argument or the `CLOUD_ML_REGION` environment variable should be set."
+            )
+
+        if base_url is None:
+            base_url = os.environ.get("ANTHROPIC_VERTEX_BASE_URL")
+            if base_url is None:
+                base_url = f"https://{region}-aiplatform.googleapis.com/v1"
+
+        super().__init__(
+            version=__version__,
+            base_url=base_url,
+            timeout=timeout,
+            max_retries=max_retries,
+            custom_headers=default_headers,
+            custom_query=default_query,
+            http_client=http_client,
+            _strict_response_validation=_strict_response_validation,
+        )
+
+        if is_given(project_id):
+            self.project_id = project_id
+
+        self.region = region
+        self.access_token = access_token
+        self.credentials = credentials
+
+        self.messages = AsyncMessages(self)
+        self.beta = AsyncBeta(self)
+
+    @override
+    async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
+        return _prepare_options(options, project_id=self.project_id, region=self.region)
+
+    @override
+    async def _prepare_request(self, request: httpx.Request) -> None:
+        if request.headers.get("Authorization"):
+            # already authenticated, nothing for us to do
+            return
+
+        request.headers["Authorization"] = f"Bearer {await self._ensure_access_token()}"
+
+    async def _ensure_access_token(self) -> str:
+        if self.access_token is not None:
+            return self.access_token
+
+        if not self.credentials:
+            self.credentials, project_id = await asyncify(load_auth)(project_id=self.project_id)
+            if not self.project_id:
+                self.project_id = project_id
+
+        if self.credentials.expired or not self.credentials.token:
+            await asyncify(refresh_auth)(self.credentials)
+
+        if not self.credentials.token:
+            raise RuntimeError("Could not resolve API token from the environment")
+
+        assert isinstance(self.credentials.token, str)
+        return self.credentials.token
+
+    def copy(
+        self,
+        *,
+        region: str | NotGiven = NOT_GIVEN,
+        project_id: str | NotGiven = NOT_GIVEN,
+        access_token: str | None = None,
+        credentials: GoogleCredentials | None = None,
+        base_url: str | httpx.URL | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+        http_client: httpx.AsyncClient | None = None,
+        max_retries: int | NotGiven = NOT_GIVEN,
+        default_headers: Mapping[str, str] | None = None,
+        set_default_headers: Mapping[str, str] | None = None,
+        default_query: Mapping[str, object] | None = None,
+        set_default_query: Mapping[str, object] | None = None,
+        _extra_kwargs: Mapping[str, Any] = {},
+    ) -> Self:
+        """
+        Create a new client instance re-using the same options given to the current client with optional overriding.
+        """
+        if default_headers is not None and set_default_headers is not None:
+            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")
+
+        if default_query is not None and set_default_query is not None:
+            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")
+
+        headers = self._custom_headers
+        if default_headers is not None:
+            headers = {**headers, **default_headers}
+        elif set_default_headers is not None:
+            headers = set_default_headers
+
+        params = self._custom_query
+        if default_query is not None:
+            params = {**params, **default_query}
+        elif set_default_query is not None:
+            params = set_default_query
+
+        http_client = http_client or self._client
+
+        return self.__class__(
+            region=region if is_given(region) else self.region,
+            project_id=project_id if is_given(project_id) else self.project_id or NOT_GIVEN,
+            access_token=access_token or self.access_token,
+            credentials=credentials or self.credentials,
+            base_url=base_url or self.base_url,
+            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
+            http_client=http_client,
+            max_retries=max_retries if is_given(max_retries) else self.max_retries,
+            default_headers=headers,
+            default_query=params,
+            **_extra_kwargs,
+        )
+
+    # Alias for `copy` for nicer inline usage, e.g.
+    # client.with_options(timeout=10).foo.create(...)
+    with_options = copy
+
+
+def _prepare_options(input_options: FinalRequestOptions, *, project_id: str | None, region: str) -> FinalRequestOptions:
+    options = model_copy(input_options, deep=True)
+
+    if is_dict(options.json_data):
+        options.json_data.setdefault("anthropic_version", DEFAULT_VERSION)
+
+    if options.url in {"/v1/messages", "/v1/messages?beta=true"} and options.method == "post":
+        if project_id is None:
+            raise RuntimeError(
+                "No project_id was given and it could not be resolved from credentials. The client should be instantiated with the `project_id` argument or the `ANTHROPIC_VERTEX_PROJECT_ID` environment variable should be set."
+            )
+
+        if not is_dict(options.json_data):
+            raise RuntimeError("Expected json data to be a dictionary for post /v1/messages")
+
+        model = options.json_data.pop("model")
+        stream = options.json_data.get("stream", False)
+        specifier = "streamRawPredict" if stream else "rawPredict"
+
+        options.url = f"/projects/{project_id}/locations/{region}/publishers/anthropic/models/{model}:{specifier}"
+
+    if options.url in {"/v1/messages/count_tokens", "/v1/messages/count_tokens?beta=true"} and options.method == "post":
+        if project_id is None:
+            raise RuntimeError(
+                "No project_id was given and it could not be resolved from credentials. The client should be instantiated with the `project_id` argument or the `ANTHROPIC_VERTEX_PROJECT_ID` environment variable should be set."
+            )
+
+        options.url = f"/projects/{project_id}/locations/{region}/publishers/anthropic/models/count-tokens:rawPredict"
+
+    if options.url.startswith("/v1/messages/batches"):
+        raise AnthropicError("The Batch API is not supported in the Vertex client yet")
+
+    return options
diff --git a/.venv/lib/python3.12/site-packages/anthropic/pagination.py b/.venv/lib/python3.12/site-packages/anthropic/pagination.py
new file mode 100644
index 00000000..c4553fba
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/pagination.py
@@ -0,0 +1,84 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Generic, TypeVar, Optional
+from typing_extensions import override
+
+from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage
+
+__all__ = ["SyncPage", "AsyncPage"]
+
+_T = TypeVar("_T")
+
+
+class SyncPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+    data: List[_T]
+    has_more: Optional[bool] = None
+    first_id: Optional[str] = None
+    last_id: Optional[str] = None
+
+    @override
+    def _get_page_items(self) -> List[_T]:
+        data = self.data
+        if not data:
+            return []
+        return data
+
+    @override
+    def has_next_page(self) -> bool:
+        has_more = self.has_more
+        if has_more is not None and has_more is False:
+            return False
+
+        return super().has_next_page()
+
+    @override
+    def next_page_info(self) -> Optional[PageInfo]:
+        if self._options.params.get("before_id"):
+            first_id = self.first_id
+            if not first_id:
+                return None
+
+            return PageInfo(params={"before_id": first_id})
+
+        last_id = self.last_id
+        if not last_id:
+            return None
+
+        return PageInfo(params={"after_id": last_id})
+
+
+class AsyncPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+    data: List[_T]
+    has_more: Optional[bool] = None
+    first_id: Optional[str] = None
+    last_id: Optional[str] = None
+
+    @override
+    def _get_page_items(self) -> List[_T]:
+        data = self.data
+        if not data:
+            return []
+        return data
+
+    @override
+    def has_next_page(self) -> bool:
+        has_more = self.has_more
+        if has_more is not None and has_more is False:
+            return False
+
+        return super().has_next_page()
+
+    @override
+    def next_page_info(self) -> Optional[PageInfo]:
+        if self._options.params.get("before_id"):
+            first_id = self.first_id
+            if not first_id:
+                return None
+
+            return PageInfo(params={"before_id": first_id})
+
+        last_id = self.last_id
+        if not last_id:
+            return None
+
+        return PageInfo(params={"after_id": last_id})
diff --git a/.venv/lib/python3.12/site-packages/anthropic/py.typed b/.venv/lib/python3.12/site-packages/anthropic/py.typed
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/py.typed
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/resources/__init__.py
new file mode 100644
index 00000000..ffff8855
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/__init__.py
@@ -0,0 +1,61 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .beta import (
+    Beta,
+    AsyncBeta,
+    BetaWithRawResponse,
+    AsyncBetaWithRawResponse,
+    BetaWithStreamingResponse,
+    AsyncBetaWithStreamingResponse,
+)
+from .models import (
+    Models,
+    AsyncModels,
+    ModelsWithRawResponse,
+    AsyncModelsWithRawResponse,
+    ModelsWithStreamingResponse,
+    AsyncModelsWithStreamingResponse,
+)
+from .messages import (
+    Messages,
+    AsyncMessages,
+    MessagesWithRawResponse,
+    AsyncMessagesWithRawResponse,
+    MessagesWithStreamingResponse,
+    AsyncMessagesWithStreamingResponse,
+)
+from .completions import (
+    Completions,
+    AsyncCompletions,
+    CompletionsWithRawResponse,
+    AsyncCompletionsWithRawResponse,
+    CompletionsWithStreamingResponse,
+    AsyncCompletionsWithStreamingResponse,
+)
+
+__all__ = [
+    "Completions",
+    "AsyncCompletions",
+    "CompletionsWithRawResponse",
+    "AsyncCompletionsWithRawResponse",
+    "CompletionsWithStreamingResponse",
+    "AsyncCompletionsWithStreamingResponse",
+    "Messages",
+    "AsyncMessages",
+    "MessagesWithRawResponse",
+    "AsyncMessagesWithRawResponse",
+    "MessagesWithStreamingResponse",
+    "AsyncMessagesWithStreamingResponse",
+    "Models",
+    "AsyncModels",
+    "ModelsWithRawResponse",
+    "AsyncModelsWithRawResponse",
+    "ModelsWithStreamingResponse",
+    "AsyncModelsWithStreamingResponse",
+    "Beta",
+    "AsyncBeta",
+    "BetaWithRawResponse",
+    "AsyncBetaWithRawResponse",
+    "BetaWithStreamingResponse",
+    "AsyncBetaWithStreamingResponse",
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/beta/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/__init__.py
new file mode 100644
index 00000000..82b343fa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/__init__.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .beta import (
+    Beta,
+    AsyncBeta,
+    BetaWithRawResponse,
+    AsyncBetaWithRawResponse,
+    BetaWithStreamingResponse,
+    AsyncBetaWithStreamingResponse,
+)
+from .models import (
+    Models,
+    AsyncModels,
+    ModelsWithRawResponse,
+    AsyncModelsWithRawResponse,
+    ModelsWithStreamingResponse,
+    AsyncModelsWithStreamingResponse,
+)
+from .messages import (
+    Messages,
+    AsyncMessages,
+    MessagesWithRawResponse,
+    AsyncMessagesWithRawResponse,
+    MessagesWithStreamingResponse,
+    AsyncMessagesWithStreamingResponse,
+)
+
+__all__ = [
+    "Models",
+    "AsyncModels",
+    "ModelsWithRawResponse",
+    "AsyncModelsWithRawResponse",
+    "ModelsWithStreamingResponse",
+    "AsyncModelsWithStreamingResponse",
+    "Messages",
+    "AsyncMessages",
+    "MessagesWithRawResponse",
+    "AsyncMessagesWithRawResponse",
+    "MessagesWithStreamingResponse",
+    "AsyncMessagesWithStreamingResponse",
+    "Beta",
+    "AsyncBeta",
+    "BetaWithRawResponse",
+    "AsyncBetaWithRawResponse",
+    "BetaWithStreamingResponse",
+    "AsyncBetaWithStreamingResponse",
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/beta/beta.py b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/beta.py
new file mode 100644
index 00000000..ae5c7d98
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/beta.py
@@ -0,0 +1,134 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .models import (
+    Models,
+    AsyncModels,
+    ModelsWithRawResponse,
+    AsyncModelsWithRawResponse,
+    ModelsWithStreamingResponse,
+    AsyncModelsWithStreamingResponse,
+)
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from .messages.messages import (
+    Messages,
+    AsyncMessages,
+    MessagesWithRawResponse,
+    AsyncMessagesWithRawResponse,
+    MessagesWithStreamingResponse,
+    AsyncMessagesWithStreamingResponse,
+)
+
+__all__ = ["Beta", "AsyncBeta"]
+
+
+class Beta(SyncAPIResource):
+    @cached_property
+    def models(self) -> Models:
+        return Models(self._client)
+
+    @cached_property
+    def messages(self) -> Messages:
+        return Messages(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> BetaWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return BetaWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> BetaWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return BetaWithStreamingResponse(self)
+
+
+class AsyncBeta(AsyncAPIResource):
+    @cached_property
+    def models(self) -> AsyncModels:
+        return AsyncModels(self._client)
+
+    @cached_property
+    def messages(self) -> AsyncMessages:
+        return AsyncMessages(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> AsyncBetaWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncBetaWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncBetaWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncBetaWithStreamingResponse(self)
+
+
+class BetaWithRawResponse:
+    def __init__(self, beta: Beta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def models(self) -> ModelsWithRawResponse:
+        return ModelsWithRawResponse(self._beta.models)
+
+    @cached_property
+    def messages(self) -> MessagesWithRawResponse:
+        return MessagesWithRawResponse(self._beta.messages)
+
+
+class AsyncBetaWithRawResponse:
+    def __init__(self, beta: AsyncBeta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def models(self) -> AsyncModelsWithRawResponse:
+        return AsyncModelsWithRawResponse(self._beta.models)
+
+    @cached_property
+    def messages(self) -> AsyncMessagesWithRawResponse:
+        return AsyncMessagesWithRawResponse(self._beta.messages)
+
+
+class BetaWithStreamingResponse:
+    def __init__(self, beta: Beta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def models(self) -> ModelsWithStreamingResponse:
+        return ModelsWithStreamingResponse(self._beta.models)
+
+    @cached_property
+    def messages(self) -> MessagesWithStreamingResponse:
+        return MessagesWithStreamingResponse(self._beta.messages)
+
+
+class AsyncBetaWithStreamingResponse:
+    def __init__(self, beta: AsyncBeta) -> None:
+        self._beta = beta
+
+    @cached_property
+    def models(self) -> AsyncModelsWithStreamingResponse:
+        return AsyncModelsWithStreamingResponse(self._beta.models)
+
+    @cached_property
+    def messages(self) -> AsyncMessagesWithStreamingResponse:
+        return AsyncMessagesWithStreamingResponse(self._beta.messages)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/__init__.py
new file mode 100644
index 00000000..34b0a923
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .batches import (
+    Batches,
+    AsyncBatches,
+    BatchesWithRawResponse,
+    AsyncBatchesWithRawResponse,
+    BatchesWithStreamingResponse,
+    AsyncBatchesWithStreamingResponse,
+)
+from .messages import (
+    Messages,
+    AsyncMessages,
+    MessagesWithRawResponse,
+    AsyncMessagesWithRawResponse,
+    MessagesWithStreamingResponse,
+    AsyncMessagesWithStreamingResponse,
+)
+
+__all__ = [
+    "Batches",
+    "AsyncBatches",
+    "BatchesWithRawResponse",
+    "AsyncBatchesWithRawResponse",
+    "BatchesWithStreamingResponse",
+    "AsyncBatchesWithStreamingResponse",
+    "Messages",
+    "AsyncMessages",
+    "MessagesWithRawResponse",
+    "AsyncMessagesWithRawResponse",
+    "MessagesWithStreamingResponse",
+    "AsyncMessagesWithStreamingResponse",
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/batches.py b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/batches.py
new file mode 100644
index 00000000..f5483ca6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/batches.py
@@ -0,0 +1,889 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List, Iterable
+from itertools import chain
+
+import httpx
+
+from .... import _legacy_response
+from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ...._utils import (
+    is_given,
+    maybe_transform,
+    strip_not_given,
+    async_maybe_transform,
+)
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ....pagination import SyncPage, AsyncPage
+from ...._exceptions import AnthropicError
+from ...._base_client import AsyncPaginator, make_request_options
+from ...._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder
+from ....types.beta.messages import batch_list_params, batch_create_params
+from ....types.anthropic_beta_param import AnthropicBetaParam
+from ....types.beta.messages.beta_message_batch import BetaMessageBatch
+from ....types.beta.messages.beta_deleted_message_batch import BetaDeletedMessageBatch
+from ....types.beta.messages.beta_message_batch_individual_response import BetaMessageBatchIndividualResponse
+
+__all__ = ["Batches", "AsyncBatches"]
+
+
+class Batches(SyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> BatchesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return BatchesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> BatchesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return BatchesWithStreamingResponse(self)
+
+    def create(
+        self,
+        *,
+        requests: Iterable[batch_create_params.Request],
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageBatch:
+        """
+        Send a batch of Message creation requests.
+
+        The Message Batches API can be used to process multiple Messages API requests at
+        once. Once a Message Batch is created, it begins processing immediately. Batches
+        can take up to 24 hours to complete.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          requests: List of requests for prompt completion. Each is an individual request to create
+              a Message.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return self._post(
+            "/v1/messages/batches?beta=true",
+            body=maybe_transform({"requests": requests}, batch_create_params.BatchCreateParams),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageBatch,
+        )
+
+    def retrieve(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageBatch:
+        """This endpoint is idempotent and can be used to poll for Message Batch
+        completion.
+
+        To access the results of a Message Batch, make a request to the
+        `results_url` field in the response.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return self._get(
+            f"/v1/messages/batches/{message_batch_id}?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageBatch,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> SyncPage[BetaMessageBatch]:
+        """List all Message Batches within a Workspace.
+
+        Most recently created batches are
+        returned first.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return self._get_api_list(
+            "/v1/messages/batches?beta=true",
+            page=SyncPage[BetaMessageBatch],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    batch_list_params.BatchListParams,
+                ),
+            ),
+            model=BetaMessageBatch,
+        )
+
+    def delete(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaDeletedMessageBatch:
+        """
+        Delete a Message Batch.
+
+        Message Batches can only be deleted once they've finished processing. If you'd
+        like to delete an in-progress batch, you must first cancel it.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return self._delete(
+            f"/v1/messages/batches/{message_batch_id}?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaDeletedMessageBatch,
+        )
+
+    def cancel(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageBatch:
+        """Batches may be canceled any time before processing ends.
+
+        Once cancellation is
+        initiated, the batch enters a `canceling` state, at which time the system may
+        complete any in-progress, non-interruptible requests before finalizing
+        cancellation.
+
+        The number of canceled requests is specified in `request_counts`. To determine
+        which requests were canceled, check the individual results within the batch.
+        Note that cancellation may not result in any canceled requests if they were
+        non-interruptible.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return self._post(
+            f"/v1/messages/batches/{message_batch_id}/cancel?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageBatch,
+        )
+
+    def results(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> JSONLDecoder[BetaMessageBatchIndividualResponse]:
+        """
+        Streams the results of a Message Batch as a `.jsonl` file.
+
+        Each line in the file is a JSON object containing the result of a single request
+        in the Message Batch. Results are not guaranteed to be in the same order as
+        requests. Use the `custom_id` field to match results to requests.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+
+        batch = self.retrieve(message_batch_id=message_batch_id)
+        if not batch.results_url:
+            raise AnthropicError(
+                f"No `results_url` for the given batch; Has it finished processing? {batch.processing_status}"
+            )
+
+        extra_headers = {"Accept": "application/binary", **(extra_headers or {})}
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return self._get(
+            batch.results_url,
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=JSONLDecoder[BetaMessageBatchIndividualResponse],
+            stream=True,
+        )
+
+
+class AsyncBatches(AsyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> AsyncBatchesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncBatchesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncBatchesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncBatchesWithStreamingResponse(self)
+
+    async def create(
+        self,
+        *,
+        requests: Iterable[batch_create_params.Request],
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageBatch:
+        """
+        Send a batch of Message creation requests.
+
+        The Message Batches API can be used to process multiple Messages API requests at
+        once. Once a Message Batch is created, it begins processing immediately. Batches
+        can take up to 24 hours to complete.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          requests: List of requests for prompt completion. Each is an individual request to create
+              a Message.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return await self._post(
+            "/v1/messages/batches?beta=true",
+            body=await async_maybe_transform({"requests": requests}, batch_create_params.BatchCreateParams),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageBatch,
+        )
+
+    async def retrieve(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageBatch:
+        """This endpoint is idempotent and can be used to poll for Message Batch
+        completion.
+
+        To access the results of a Message Batch, make a request to the
+        `results_url` field in the response.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return await self._get(
+            f"/v1/messages/batches/{message_batch_id}?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageBatch,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncPaginator[BetaMessageBatch, AsyncPage[BetaMessageBatch]]:
+        """List all Message Batches within a Workspace.
+
+        Most recently created batches are
+        returned first.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return self._get_api_list(
+            "/v1/messages/batches?beta=true",
+            page=AsyncPage[BetaMessageBatch],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    batch_list_params.BatchListParams,
+                ),
+            ),
+            model=BetaMessageBatch,
+        )
+
+    async def delete(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaDeletedMessageBatch:
+        """
+        Delete a Message Batch.
+
+        Message Batches can only be deleted once they've finished processing. If you'd
+        like to delete an in-progress batch, you must first cancel it.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return await self._delete(
+            f"/v1/messages/batches/{message_batch_id}?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaDeletedMessageBatch,
+        )
+
+    async def cancel(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageBatch:
+        """Batches may be canceled any time before processing ends.
+
+        Once cancellation is
+        initiated, the batch enters a `canceling` state, at which time the system may
+        complete any in-progress, non-interruptible requests before finalizing
+        cancellation.
+
+        The number of canceled requests is specified in `request_counts`. To determine
+        which requests were canceled, check the individual results within the batch.
+        Note that cancellation may not result in any canceled requests if they were
+        non-interruptible.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return await self._post(
+            f"/v1/messages/batches/{message_batch_id}/cancel?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageBatch,
+        )
+
+    async def results(
+        self,
+        message_batch_id: str,
+        *,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncJSONLDecoder[BetaMessageBatchIndividualResponse]:
+        """
+        Streams the results of a Message Batch as a `.jsonl` file.
+
+        Each line in the file is a JSON object containing the result of a single request
+        in the Message Batch. Results are not guaranteed to be in the same order as
+        requests. Use the `custom_id` field to match results to requests.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+
+        batch = await self.retrieve(message_batch_id=message_batch_id)
+        if not batch.results_url:
+            raise AnthropicError(
+                f"No `results_url` for the given batch; Has it finished processing? {batch.processing_status}"
+            )
+
+        extra_headers = {"Accept": "application/binary", **(extra_headers or {})}
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["message-batches-2024-09-24"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "message-batches-2024-09-24", **(extra_headers or {})}
+        return await self._get(
+            batch.results_url,
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=AsyncJSONLDecoder[BetaMessageBatchIndividualResponse],
+            stream=True,
+        )
+
+
+class BatchesWithRawResponse:
+    def __init__(self, batches: Batches) -> None:
+        self._batches = batches
+
+        self.create = _legacy_response.to_raw_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = _legacy_response.to_raw_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = _legacy_response.to_raw_response_wrapper(
+            batches.list,
+        )
+        self.delete = _legacy_response.to_raw_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = _legacy_response.to_raw_response_wrapper(
+            batches.cancel,
+        )
+
+
+class AsyncBatchesWithRawResponse:
+    def __init__(self, batches: AsyncBatches) -> None:
+        self._batches = batches
+
+        self.create = _legacy_response.async_to_raw_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = _legacy_response.async_to_raw_response_wrapper(
+            batches.list,
+        )
+        self.delete = _legacy_response.async_to_raw_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = _legacy_response.async_to_raw_response_wrapper(
+            batches.cancel,
+        )
+
+
+class BatchesWithStreamingResponse:
+    def __init__(self, batches: Batches) -> None:
+        self._batches = batches
+
+        self.create = to_streamed_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = to_streamed_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = to_streamed_response_wrapper(
+            batches.list,
+        )
+        self.delete = to_streamed_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = to_streamed_response_wrapper(
+            batches.cancel,
+        )
+
+
+class AsyncBatchesWithStreamingResponse:
+    def __init__(self, batches: AsyncBatches) -> None:
+        self._batches = batches
+
+        self.create = async_to_streamed_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = async_to_streamed_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = async_to_streamed_response_wrapper(
+            batches.list,
+        )
+        self.delete = async_to_streamed_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = async_to_streamed_response_wrapper(
+            batches.cancel,
+        )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/messages.py b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/messages.py
new file mode 100644
index 00000000..c1c2ef06
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/messages/messages.py
@@ -0,0 +1,2587 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import warnings
+from typing import List, Union, Iterable
+from functools import partial
+from itertools import chain
+from typing_extensions import Literal, overload
+
+import httpx
+
+from .... import _legacy_response
+from .batches import (
+    Batches,
+    AsyncBatches,
+    BatchesWithRawResponse,
+    AsyncBatchesWithRawResponse,
+    BatchesWithStreamingResponse,
+    AsyncBatchesWithStreamingResponse,
+)
+from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ...._utils import (
+    is_given,
+    required_args,
+    maybe_transform,
+    strip_not_given,
+    async_maybe_transform,
+)
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...._constants import DEFAULT_TIMEOUT
+from ...._streaming import Stream, AsyncStream
+from ....types.beta import (
+    BetaThinkingConfigParam,
+    message_create_params,
+    message_count_tokens_params,
+)
+from ...._base_client import make_request_options
+from ....lib.streaming import BetaMessageStreamManager, BetaAsyncMessageStreamManager
+from ...messages.messages import DEPRECATED_MODELS
+from ....types.model_param import ModelParam
+from ....types.beta.beta_message import BetaMessage
+from ....types.anthropic_beta_param import AnthropicBetaParam
+from ....types.beta.beta_message_param import BetaMessageParam
+from ....types.beta.beta_metadata_param import BetaMetadataParam
+from ....types.beta.beta_text_block_param import BetaTextBlockParam
+from ....types.beta.beta_tool_union_param import BetaToolUnionParam
+from ....types.beta.beta_tool_choice_param import BetaToolChoiceParam
+from ....types.beta.beta_message_tokens_count import BetaMessageTokensCount
+from ....types.beta.beta_thinking_config_param import BetaThinkingConfigParam
+from ....types.beta.beta_raw_message_stream_event import BetaRawMessageStreamEvent
+
+__all__ = ["Messages", "AsyncMessages"]
+
+
+class Messages(SyncAPIResource):
+    @cached_property
+    def batches(self) -> Batches:
+        return Batches(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> MessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return MessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> MessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return MessagesWithStreamingResponse(self)
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessage:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        stream: Literal[True],
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Stream[BetaRawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        stream: bool,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessage | Stream[BetaRawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @required_args(["max_tokens", "messages", "model"], ["max_tokens", "messages", "model", "stream"])
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessage | Stream[BetaRawMessageStreamEvent]:
+        if not stream and not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
+            timeout = self._client._calculate_nonstreaming_timeout(max_tokens)
+
+        if model in DEPRECATED_MODELS:
+            warnings.warn(
+                f"The model '{model}' is deprecated and will reach end-of-life on {DEPRECATED_MODELS[model]}.\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.",
+                DeprecationWarning,
+                stacklevel=3,
+            )
+
+        extra_headers = {
+            **strip_not_given({"anthropic-beta": ",".join(str(e) for e in betas) if is_given(betas) else NOT_GIVEN}),
+            **(extra_headers or {}),
+        }
+        return self._post(
+            "/v1/messages?beta=true",
+            body=maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "stream": stream,
+                    "system": system,
+                    "temperature": temperature,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessage,
+            stream=stream or False,
+            stream_cls=Stream[BetaRawMessageStreamEvent],
+        )
+
+    def stream(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageStreamManager:
+        """Create a Message stream"""
+        extra_headers = {
+            "X-Stainless-Stream-Helper": "beta.messages",
+            **strip_not_given({"anthropic-beta": ",".join(str(e) for e in betas) if is_given(betas) else NOT_GIVEN}),
+            **(extra_headers or {}),
+        }
+        make_request = partial(
+            self._post,
+            "/v1/messages?beta=true",
+            body=maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "system": system,
+                    "temperature": temperature,
+                    "thinking": thinking,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                    "tools": tools,
+                    "tool_choice": tool_choice,
+                    "stream": True,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessage,
+            stream=True,
+            stream_cls=Stream[BetaRawMessageStreamEvent],
+        )
+        return BetaMessageStreamManager(make_request)
+
+    def count_tokens(
+        self,
+        *,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[message_count_tokens_params.Tool] | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageTokensCount:
+        """
+        Count the number of tokens in a Message.
+
+        The Token Count API can be used to count the number of tokens in a Message,
+        including tools, images, and documents, without creating it.
+
+        Learn more about token counting in our
+        [user guide](/en/docs/build-with-claude/token-counting)
+
+        Args:
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["token-counting-2024-11-01"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "token-counting-2024-11-01", **(extra_headers or {})}
+        return self._post(
+            "/v1/messages/count_tokens?beta=true",
+            body=maybe_transform(
+                {
+                    "messages": messages,
+                    "model": model,
+                    "system": system,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                },
+                message_count_tokens_params.MessageCountTokensParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageTokensCount,
+        )
+
+
+class AsyncMessages(AsyncAPIResource):
+    @cached_property
+    def batches(self) -> AsyncBatches:
+        return AsyncBatches(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> AsyncMessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncMessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncMessagesWithStreamingResponse(self)
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessage:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        stream: Literal[True],
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncStream[BetaRawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        stream: bool,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessage | AsyncStream[BetaRawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @required_args(["max_tokens", "messages", "model"], ["max_tokens", "messages", "model", "stream"])
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessage | AsyncStream[BetaRawMessageStreamEvent]:
+        if not stream and not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
+            timeout = self._client._calculate_nonstreaming_timeout(max_tokens)
+
+        if model in DEPRECATED_MODELS:
+            warnings.warn(
+                f"The model '{model}' is deprecated and will reach end-of-life on {DEPRECATED_MODELS[model]}.\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.",
+                DeprecationWarning,
+                stacklevel=3,
+            )
+
+        extra_headers = {
+            **strip_not_given({"anthropic-beta": ",".join(str(e) for e in betas) if is_given(betas) else NOT_GIVEN}),
+            **(extra_headers or {}),
+        }
+        return await self._post(
+            "/v1/messages?beta=true",
+            body=await async_maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "stream": stream,
+                    "system": system,
+                    "temperature": temperature,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessage,
+            stream=stream or False,
+            stream_cls=AsyncStream[BetaRawMessageStreamEvent],
+        )
+
+    def stream(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        metadata: BetaMetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[BetaToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaAsyncMessageStreamManager:
+        extra_headers = {
+            "X-Stainless-Stream-Helper": "beta.messages",
+            **strip_not_given({"anthropic-beta": ",".join(str(e) for e in betas) if is_given(betas) else NOT_GIVEN}),
+            **(extra_headers or {}),
+        }
+        request = self._post(
+            "/v1/messages",
+            body=maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "system": system,
+                    "temperature": temperature,
+                    "thinking": thinking,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                    "tools": tools,
+                    "tool_choice": tool_choice,
+                    "stream": True,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessage,
+            stream=True,
+            stream_cls=AsyncStream[BetaRawMessageStreamEvent],
+        )
+        return BetaAsyncMessageStreamManager(request)
+
+    async def count_tokens(
+        self,
+        *,
+        messages: Iterable[BetaMessageParam],
+        model: ModelParam,
+        system: Union[str, Iterable[BetaTextBlockParam]] | NotGiven = NOT_GIVEN,
+        thinking: BetaThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: BetaToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[message_count_tokens_params.Tool] | NotGiven = NOT_GIVEN,
+        betas: List[AnthropicBetaParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaMessageTokensCount:
+        """
+        Count the number of tokens in a Message.
+
+        The Token Count API can be used to count the number of tokens in a Message,
+        including tools, images, and documents, without creating it.
+
+        Learn more about token counting in our
+        [user guide](/en/docs/build-with-claude/token-counting)
+
+        Args:
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          betas: Optional header to specify the beta version(s) you want to use.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        extra_headers = {
+            **strip_not_given(
+                {
+                    "anthropic-beta": ",".join(chain((str(e) for e in betas), ["token-counting-2024-11-01"]))
+                    if is_given(betas)
+                    else NOT_GIVEN
+                }
+            ),
+            **(extra_headers or {}),
+        }
+        extra_headers = {"anthropic-beta": "token-counting-2024-11-01", **(extra_headers or {})}
+        return await self._post(
+            "/v1/messages/count_tokens?beta=true",
+            body=await async_maybe_transform(
+                {
+                    "messages": messages,
+                    "model": model,
+                    "system": system,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                },
+                message_count_tokens_params.MessageCountTokensParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaMessageTokensCount,
+        )
+
+
+class MessagesWithRawResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.to_raw_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = _legacy_response.to_raw_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> BatchesWithRawResponse:
+        return BatchesWithRawResponse(self._messages.batches)
+
+
+class AsyncMessagesWithRawResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.async_to_raw_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = _legacy_response.async_to_raw_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> AsyncBatchesWithRawResponse:
+        return AsyncBatchesWithRawResponse(self._messages.batches)
+
+
+class MessagesWithStreamingResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = to_streamed_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = to_streamed_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> BatchesWithStreamingResponse:
+        return BatchesWithStreamingResponse(self._messages.batches)
+
+
+class AsyncMessagesWithStreamingResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = async_to_streamed_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = async_to_streamed_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> AsyncBatchesWithStreamingResponse:
+        return AsyncBatchesWithStreamingResponse(self._messages.batches)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/beta/models.py b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/models.py
new file mode 100644
index 00000000..04d620c5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/beta/models.py
@@ -0,0 +1,300 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ... import _legacy_response
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._utils import maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...pagination import SyncPage, AsyncPage
+from ...types.beta import model_list_params
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.beta.beta_model_info import BetaModelInfo
+
+__all__ = ["Models", "AsyncModels"]
+
+
+class Models(SyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> ModelsWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return ModelsWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> ModelsWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return ModelsWithStreamingResponse(self)
+
+    def retrieve(
+        self,
+        model_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaModelInfo:
+        """
+        Get a specific model.
+
+        The Models API response can be used to determine information about a specific
+        model or resolve a model alias to a model ID.
+
+        Args:
+          model_id: Model identifier or alias.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not model_id:
+            raise ValueError(f"Expected a non-empty value for `model_id` but received {model_id!r}")
+        return self._get(
+            f"/v1/models/{model_id}?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaModelInfo,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> SyncPage[BetaModelInfo]:
+        """
+        List available models.
+
+        The Models API response can be used to determine which models are available for
+        use in the API. More recently released models are listed first.
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._get_api_list(
+            "/v1/models?beta=true",
+            page=SyncPage[BetaModelInfo],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    model_list_params.ModelListParams,
+                ),
+            ),
+            model=BetaModelInfo,
+        )
+
+
+class AsyncModels(AsyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> AsyncModelsWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncModelsWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncModelsWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncModelsWithStreamingResponse(self)
+
+    async def retrieve(
+        self,
+        model_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> BetaModelInfo:
+        """
+        Get a specific model.
+
+        The Models API response can be used to determine information about a specific
+        model or resolve a model alias to a model ID.
+
+        Args:
+          model_id: Model identifier or alias.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not model_id:
+            raise ValueError(f"Expected a non-empty value for `model_id` but received {model_id!r}")
+        return await self._get(
+            f"/v1/models/{model_id}?beta=true",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=BetaModelInfo,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncPaginator[BetaModelInfo, AsyncPage[BetaModelInfo]]:
+        """
+        List available models.
+
+        The Models API response can be used to determine which models are available for
+        use in the API. More recently released models are listed first.
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._get_api_list(
+            "/v1/models?beta=true",
+            page=AsyncPage[BetaModelInfo],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    model_list_params.ModelListParams,
+                ),
+            ),
+            model=BetaModelInfo,
+        )
+
+
+class ModelsWithRawResponse:
+    def __init__(self, models: Models) -> None:
+        self._models = models
+
+        self.retrieve = _legacy_response.to_raw_response_wrapper(
+            models.retrieve,
+        )
+        self.list = _legacy_response.to_raw_response_wrapper(
+            models.list,
+        )
+
+
+class AsyncModelsWithRawResponse:
+    def __init__(self, models: AsyncModels) -> None:
+        self._models = models
+
+        self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+            models.retrieve,
+        )
+        self.list = _legacy_response.async_to_raw_response_wrapper(
+            models.list,
+        )
+
+
+class ModelsWithStreamingResponse:
+    def __init__(self, models: Models) -> None:
+        self._models = models
+
+        self.retrieve = to_streamed_response_wrapper(
+            models.retrieve,
+        )
+        self.list = to_streamed_response_wrapper(
+            models.list,
+        )
+
+
+class AsyncModelsWithStreamingResponse:
+    def __init__(self, models: AsyncModels) -> None:
+        self._models = models
+
+        self.retrieve = async_to_streamed_response_wrapper(
+            models.retrieve,
+        )
+        self.list = async_to_streamed_response_wrapper(
+            models.list,
+        )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/completions.py b/.venv/lib/python3.12/site-packages/anthropic/resources/completions.py
new file mode 100644
index 00000000..67e3977e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/completions.py
@@ -0,0 +1,823 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Literal, overload
+
+import httpx
+
+from .. import _legacy_response
+from ..types import completion_create_params
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from .._utils import (
+    is_given,
+    required_args,
+    maybe_transform,
+    async_maybe_transform,
+)
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from .._constants import DEFAULT_TIMEOUT
+from .._streaming import Stream, AsyncStream
+from .._base_client import make_request_options
+from ..types.completion import Completion
+from ..types.model_param import ModelParam
+from ..types.metadata_param import MetadataParam
+
+__all__ = ["Completions", "AsyncCompletions"]
+
+
+class Completions(SyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> CompletionsWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return CompletionsWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> CompletionsWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return CompletionsWithStreamingResponse(self)
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Completion:
+        """[Legacy] Create a Text Completion.
+
+        The Text Completions API is a legacy API.
+
+        We recommend using the
+        [Messages API](https://docs.anthropic.com/en/api/messages) going forward.
+
+        Future models and features will not be compatible with Text Completions. See our
+        [migration guide](https://docs.anthropic.com/en/api/migrating-from-text-completions-to-messages)
+        for guidance in migrating from Text Completions to Messages.
+
+        Args:
+          max_tokens_to_sample: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          prompt: The prompt that you want Claude to complete.
+
+              For proper response generation you will need to format your prompt using
+              alternating `\n\nHuman:` and `\n\nAssistant:` conversational turns. For example:
+
+              ```
+              "\n\nHuman: {userQuestion}\n\nAssistant:"
+              ```
+
+              See [prompt validation](https://docs.anthropic.com/en/api/prompt-validation) and
+              our guide to
+              [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Sequences that will cause the model to stop generating.
+
+              Our models stop on `"\n\nHuman:"`, and may include additional built-in stop
+              sequences in the future. By providing the stop_sequences parameter, you may
+              include additional strings that will cause the model to stop generating.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        stream: Literal[True],
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Stream[Completion]:
+        """[Legacy] Create a Text Completion.
+
+        The Text Completions API is a legacy API.
+
+        We recommend using the
+        [Messages API](https://docs.anthropic.com/en/api/messages) going forward.
+
+        Future models and features will not be compatible with Text Completions. See our
+        [migration guide](https://docs.anthropic.com/en/api/migrating-from-text-completions-to-messages)
+        for guidance in migrating from Text Completions to Messages.
+
+        Args:
+          max_tokens_to_sample: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          prompt: The prompt that you want Claude to complete.
+
+              For proper response generation you will need to format your prompt using
+              alternating `\n\nHuman:` and `\n\nAssistant:` conversational turns. For example:
+
+              ```
+              "\n\nHuman: {userQuestion}\n\nAssistant:"
+              ```
+
+              See [prompt validation](https://docs.anthropic.com/en/api/prompt-validation) and
+              our guide to
+              [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more
+              details.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Sequences that will cause the model to stop generating.
+
+              Our models stop on `"\n\nHuman:"`, and may include additional built-in stop
+              sequences in the future. By providing the stop_sequences parameter, you may
+              include additional strings that will cause the model to stop generating.
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        stream: bool,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Completion | Stream[Completion]:
+        """[Legacy] Create a Text Completion.
+
+        The Text Completions API is a legacy API.
+
+        We recommend using the
+        [Messages API](https://docs.anthropic.com/en/api/messages) going forward.
+
+        Future models and features will not be compatible with Text Completions. See our
+        [migration guide](https://docs.anthropic.com/en/api/migrating-from-text-completions-to-messages)
+        for guidance in migrating from Text Completions to Messages.
+
+        Args:
+          max_tokens_to_sample: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          prompt: The prompt that you want Claude to complete.
+
+              For proper response generation you will need to format your prompt using
+              alternating `\n\nHuman:` and `\n\nAssistant:` conversational turns. For example:
+
+              ```
+              "\n\nHuman: {userQuestion}\n\nAssistant:"
+              ```
+
+              See [prompt validation](https://docs.anthropic.com/en/api/prompt-validation) and
+              our guide to
+              [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more
+              details.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Sequences that will cause the model to stop generating.
+
+              Our models stop on `"\n\nHuman:"`, and may include additional built-in stop
+              sequences in the future. By providing the stop_sequences parameter, you may
+              include additional strings that will cause the model to stop generating.
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @required_args(["max_tokens_to_sample", "model", "prompt"], ["max_tokens_to_sample", "model", "prompt", "stream"])
+    def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Completion | Stream[Completion]:
+        if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
+            timeout = 600
+        return self._post(
+            "/v1/complete",
+            body=maybe_transform(
+                {
+                    "max_tokens_to_sample": max_tokens_to_sample,
+                    "model": model,
+                    "prompt": prompt,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "stream": stream,
+                    "temperature": temperature,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                },
+                completion_create_params.CompletionCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=Completion,
+            stream=stream or False,
+            stream_cls=Stream[Completion],
+        )
+
+
+class AsyncCompletions(AsyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> AsyncCompletionsWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncCompletionsWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncCompletionsWithStreamingResponse(self)
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Completion:
+        """[Legacy] Create a Text Completion.
+
+        The Text Completions API is a legacy API.
+
+        We recommend using the
+        [Messages API](https://docs.anthropic.com/en/api/messages) going forward.
+
+        Future models and features will not be compatible with Text Completions. See our
+        [migration guide](https://docs.anthropic.com/en/api/migrating-from-text-completions-to-messages)
+        for guidance in migrating from Text Completions to Messages.
+
+        Args:
+          max_tokens_to_sample: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          prompt: The prompt that you want Claude to complete.
+
+              For proper response generation you will need to format your prompt using
+              alternating `\n\nHuman:` and `\n\nAssistant:` conversational turns. For example:
+
+              ```
+              "\n\nHuman: {userQuestion}\n\nAssistant:"
+              ```
+
+              See [prompt validation](https://docs.anthropic.com/en/api/prompt-validation) and
+              our guide to
+              [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Sequences that will cause the model to stop generating.
+
+              Our models stop on `"\n\nHuman:"`, and may include additional built-in stop
+              sequences in the future. By providing the stop_sequences parameter, you may
+              include additional strings that will cause the model to stop generating.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        stream: Literal[True],
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncStream[Completion]:
+        """[Legacy] Create a Text Completion.
+
+        The Text Completions API is a legacy API.
+
+        We recommend using the
+        [Messages API](https://docs.anthropic.com/en/api/messages) going forward.
+
+        Future models and features will not be compatible with Text Completions. See our
+        [migration guide](https://docs.anthropic.com/en/api/migrating-from-text-completions-to-messages)
+        for guidance in migrating from Text Completions to Messages.
+
+        Args:
+          max_tokens_to_sample: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          prompt: The prompt that you want Claude to complete.
+
+              For proper response generation you will need to format your prompt using
+              alternating `\n\nHuman:` and `\n\nAssistant:` conversational turns. For example:
+
+              ```
+              "\n\nHuman: {userQuestion}\n\nAssistant:"
+              ```
+
+              See [prompt validation](https://docs.anthropic.com/en/api/prompt-validation) and
+              our guide to
+              [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more
+              details.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Sequences that will cause the model to stop generating.
+
+              Our models stop on `"\n\nHuman:"`, and may include additional built-in stop
+              sequences in the future. By providing the stop_sequences parameter, you may
+              include additional strings that will cause the model to stop generating.
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        stream: bool,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Completion | AsyncStream[Completion]:
+        """[Legacy] Create a Text Completion.
+
+        The Text Completions API is a legacy API.
+
+        We recommend using the
+        [Messages API](https://docs.anthropic.com/en/api/messages) going forward.
+
+        Future models and features will not be compatible with Text Completions. See our
+        [migration guide](https://docs.anthropic.com/en/api/migrating-from-text-completions-to-messages)
+        for guidance in migrating from Text Completions to Messages.
+
+        Args:
+          max_tokens_to_sample: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          prompt: The prompt that you want Claude to complete.
+
+              For proper response generation you will need to format your prompt using
+              alternating `\n\nHuman:` and `\n\nAssistant:` conversational turns. For example:
+
+              ```
+              "\n\nHuman: {userQuestion}\n\nAssistant:"
+              ```
+
+              See [prompt validation](https://docs.anthropic.com/en/api/prompt-validation) and
+              our guide to
+              [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more
+              details.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Sequences that will cause the model to stop generating.
+
+              Our models stop on `"\n\nHuman:"`, and may include additional built-in stop
+              sequences in the future. By providing the stop_sequences parameter, you may
+              include additional strings that will cause the model to stop generating.
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @required_args(["max_tokens_to_sample", "model", "prompt"], ["max_tokens_to_sample", "model", "prompt", "stream"])
+    async def create(
+        self,
+        *,
+        max_tokens_to_sample: int,
+        model: ModelParam,
+        prompt: str,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Completion | AsyncStream[Completion]:
+        if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
+            timeout = 600
+        return await self._post(
+            "/v1/complete",
+            body=await async_maybe_transform(
+                {
+                    "max_tokens_to_sample": max_tokens_to_sample,
+                    "model": model,
+                    "prompt": prompt,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "stream": stream,
+                    "temperature": temperature,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                },
+                completion_create_params.CompletionCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=Completion,
+            stream=stream or False,
+            stream_cls=AsyncStream[Completion],
+        )
+
+
+class CompletionsWithRawResponse:
+    def __init__(self, completions: Completions) -> None:
+        self._completions = completions
+
+        self.create = _legacy_response.to_raw_response_wrapper(
+            completions.create,
+        )
+
+
+class AsyncCompletionsWithRawResponse:
+    def __init__(self, completions: AsyncCompletions) -> None:
+        self._completions = completions
+
+        self.create = _legacy_response.async_to_raw_response_wrapper(
+            completions.create,
+        )
+
+
+class CompletionsWithStreamingResponse:
+    def __init__(self, completions: Completions) -> None:
+        self._completions = completions
+
+        self.create = to_streamed_response_wrapper(
+            completions.create,
+        )
+
+
+class AsyncCompletionsWithStreamingResponse:
+    def __init__(self, completions: AsyncCompletions) -> None:
+        self._completions = completions
+
+        self.create = async_to_streamed_response_wrapper(
+            completions.create,
+        )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/messages/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/resources/messages/__init__.py
new file mode 100644
index 00000000..6e7cf9d9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/messages/__init__.py
@@ -0,0 +1,35 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .batches import (
+    Batches,
+    AsyncBatches,
+    BatchesWithRawResponse,
+    AsyncBatchesWithRawResponse,
+    BatchesWithStreamingResponse,
+    AsyncBatchesWithStreamingResponse,
+)
+from .messages import (
+    DEPRECATED_MODELS,
+    Messages,
+    AsyncMessages,
+    MessagesWithRawResponse,
+    AsyncMessagesWithRawResponse,
+    MessagesWithStreamingResponse,
+    AsyncMessagesWithStreamingResponse,
+)
+
+__all__ = [
+    "Batches",
+    "AsyncBatches",
+    "BatchesWithRawResponse",
+    "AsyncBatchesWithRawResponse",
+    "BatchesWithStreamingResponse",
+    "AsyncBatchesWithStreamingResponse",
+    "Messages",
+    "AsyncMessages",
+    "MessagesWithRawResponse",
+    "AsyncMessagesWithRawResponse",
+    "MessagesWithStreamingResponse",
+    "AsyncMessagesWithStreamingResponse",
+    "DEPRECATED_MODELS",
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/messages/batches.py b/.venv/lib/python3.12/site-packages/anthropic/resources/messages/batches.py
new file mode 100644
index 00000000..4ebd8fd4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/messages/batches.py
@@ -0,0 +1,717 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable
+
+import httpx
+
+from ... import _legacy_response
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._utils import (
+    maybe_transform,
+    async_maybe_transform,
+)
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...pagination import SyncPage, AsyncPage
+from ..._exceptions import AnthropicError
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.messages import batch_list_params, batch_create_params
+from ..._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder
+from ...types.messages.message_batch import MessageBatch
+from ...types.messages.deleted_message_batch import DeletedMessageBatch
+from ...types.messages.message_batch_individual_response import MessageBatchIndividualResponse
+
+__all__ = ["Batches", "AsyncBatches"]
+
+
+class Batches(SyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> BatchesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return BatchesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> BatchesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return BatchesWithStreamingResponse(self)
+
+    def create(
+        self,
+        *,
+        requests: Iterable[batch_create_params.Request],
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageBatch:
+        """
+        Send a batch of Message creation requests.
+
+        The Message Batches API can be used to process multiple Messages API requests at
+        once. Once a Message Batch is created, it begins processing immediately. Batches
+        can take up to 24 hours to complete.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          requests: List of requests for prompt completion. Each is an individual request to create
+              a Message.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._post(
+            "/v1/messages/batches",
+            body=maybe_transform({"requests": requests}, batch_create_params.BatchCreateParams),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageBatch,
+        )
+
+    def retrieve(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageBatch:
+        """This endpoint is idempotent and can be used to poll for Message Batch
+        completion.
+
+        To access the results of a Message Batch, make a request to the
+        `results_url` field in the response.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        return self._get(
+            f"/v1/messages/batches/{message_batch_id}",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageBatch,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> SyncPage[MessageBatch]:
+        """List all Message Batches within a Workspace.
+
+        Most recently created batches are
+        returned first.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._get_api_list(
+            "/v1/messages/batches",
+            page=SyncPage[MessageBatch],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    batch_list_params.BatchListParams,
+                ),
+            ),
+            model=MessageBatch,
+        )
+
+    def delete(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> DeletedMessageBatch:
+        """
+        Delete a Message Batch.
+
+        Message Batches can only be deleted once they've finished processing. If you'd
+        like to delete an in-progress batch, you must first cancel it.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        return self._delete(
+            f"/v1/messages/batches/{message_batch_id}",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=DeletedMessageBatch,
+        )
+
+    def cancel(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageBatch:
+        """Batches may be canceled any time before processing ends.
+
+        Once cancellation is
+        initiated, the batch enters a `canceling` state, at which time the system may
+        complete any in-progress, non-interruptible requests before finalizing
+        cancellation.
+
+        The number of canceled requests is specified in `request_counts`. To determine
+        which requests were canceled, check the individual results within the batch.
+        Note that cancellation may not result in any canceled requests if they were
+        non-interruptible.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        return self._post(
+            f"/v1/messages/batches/{message_batch_id}/cancel",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageBatch,
+        )
+
+    def results(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> JSONLDecoder[MessageBatchIndividualResponse]:
+        """
+        Streams the results of a Message Batch as a `.jsonl` file.
+
+        Each line in the file is a JSON object containing the result of a single request
+        in the Message Batch. Results are not guaranteed to be in the same order as
+        requests. Use the `custom_id` field to match results to requests.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+
+        batch = self.retrieve(message_batch_id=message_batch_id)
+        if not batch.results_url:
+            raise AnthropicError(
+                f"No `results_url` for the given batch; Has it finished processing? {batch.processing_status}"
+            )
+
+        extra_headers = {"Accept": "application/binary", **(extra_headers or {})}
+        return self._get(
+            batch.results_url,
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=JSONLDecoder[MessageBatchIndividualResponse],
+            stream=True,
+        )
+
+
+class AsyncBatches(AsyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> AsyncBatchesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncBatchesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncBatchesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncBatchesWithStreamingResponse(self)
+
+    async def create(
+        self,
+        *,
+        requests: Iterable[batch_create_params.Request],
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageBatch:
+        """
+        Send a batch of Message creation requests.
+
+        The Message Batches API can be used to process multiple Messages API requests at
+        once. Once a Message Batch is created, it begins processing immediately. Batches
+        can take up to 24 hours to complete.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          requests: List of requests for prompt completion. Each is an individual request to create
+              a Message.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return await self._post(
+            "/v1/messages/batches",
+            body=await async_maybe_transform({"requests": requests}, batch_create_params.BatchCreateParams),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageBatch,
+        )
+
+    async def retrieve(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageBatch:
+        """This endpoint is idempotent and can be used to poll for Message Batch
+        completion.
+
+        To access the results of a Message Batch, make a request to the
+        `results_url` field in the response.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        return await self._get(
+            f"/v1/messages/batches/{message_batch_id}",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageBatch,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncPaginator[MessageBatch, AsyncPage[MessageBatch]]:
+        """List all Message Batches within a Workspace.
+
+        Most recently created batches are
+        returned first.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._get_api_list(
+            "/v1/messages/batches",
+            page=AsyncPage[MessageBatch],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    batch_list_params.BatchListParams,
+                ),
+            ),
+            model=MessageBatch,
+        )
+
+    async def delete(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> DeletedMessageBatch:
+        """
+        Delete a Message Batch.
+
+        Message Batches can only be deleted once they've finished processing. If you'd
+        like to delete an in-progress batch, you must first cancel it.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        return await self._delete(
+            f"/v1/messages/batches/{message_batch_id}",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=DeletedMessageBatch,
+        )
+
+    async def cancel(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageBatch:
+        """Batches may be canceled any time before processing ends.
+
+        Once cancellation is
+        initiated, the batch enters a `canceling` state, at which time the system may
+        complete any in-progress, non-interruptible requests before finalizing
+        cancellation.
+
+        The number of canceled requests is specified in `request_counts`. To determine
+        which requests were canceled, check the individual results within the batch.
+        Note that cancellation may not result in any canceled requests if they were
+        non-interruptible.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+        return await self._post(
+            f"/v1/messages/batches/{message_batch_id}/cancel",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageBatch,
+        )
+
+    async def results(
+        self,
+        message_batch_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncJSONLDecoder[MessageBatchIndividualResponse]:
+        """
+        Streams the results of a Message Batch as a `.jsonl` file.
+
+        Each line in the file is a JSON object containing the result of a single request
+        in the Message Batch. Results are not guaranteed to be in the same order as
+        requests. Use the `custom_id` field to match results to requests.
+
+        Learn more about the Message Batches API in our
+        [user guide](/en/docs/build-with-claude/batch-processing)
+
+        Args:
+          message_batch_id: ID of the Message Batch.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not message_batch_id:
+            raise ValueError(f"Expected a non-empty value for `message_batch_id` but received {message_batch_id!r}")
+
+        batch = await self.retrieve(message_batch_id=message_batch_id)
+        if not batch.results_url:
+            raise AnthropicError(
+                f"No `results_url` for the given batch; Has it finished processing? {batch.processing_status}"
+            )
+
+        extra_headers = {"Accept": "application/binary", **(extra_headers or {})}
+        return await self._get(
+            batch.results_url,
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=AsyncJSONLDecoder[MessageBatchIndividualResponse],
+            stream=True,
+        )
+
+
+class BatchesWithRawResponse:
+    def __init__(self, batches: Batches) -> None:
+        self._batches = batches
+
+        self.create = _legacy_response.to_raw_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = _legacy_response.to_raw_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = _legacy_response.to_raw_response_wrapper(
+            batches.list,
+        )
+        self.delete = _legacy_response.to_raw_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = _legacy_response.to_raw_response_wrapper(
+            batches.cancel,
+        )
+
+
+class AsyncBatchesWithRawResponse:
+    def __init__(self, batches: AsyncBatches) -> None:
+        self._batches = batches
+
+        self.create = _legacy_response.async_to_raw_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = _legacy_response.async_to_raw_response_wrapper(
+            batches.list,
+        )
+        self.delete = _legacy_response.async_to_raw_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = _legacy_response.async_to_raw_response_wrapper(
+            batches.cancel,
+        )
+
+
+class BatchesWithStreamingResponse:
+    def __init__(self, batches: Batches) -> None:
+        self._batches = batches
+
+        self.create = to_streamed_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = to_streamed_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = to_streamed_response_wrapper(
+            batches.list,
+        )
+        self.delete = to_streamed_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = to_streamed_response_wrapper(
+            batches.cancel,
+        )
+
+
+class AsyncBatchesWithStreamingResponse:
+    def __init__(self, batches: AsyncBatches) -> None:
+        self._batches = batches
+
+        self.create = async_to_streamed_response_wrapper(
+            batches.create,
+        )
+        self.retrieve = async_to_streamed_response_wrapper(
+            batches.retrieve,
+        )
+        self.list = async_to_streamed_response_wrapper(
+            batches.list,
+        )
+        self.delete = async_to_streamed_response_wrapper(
+            batches.delete,
+        )
+        self.cancel = async_to_streamed_response_wrapper(
+            batches.cancel,
+        )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/messages/messages.py b/.venv/lib/python3.12/site-packages/anthropic/resources/messages/messages.py
new file mode 100644
index 00000000..70bceb7f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/messages/messages.py
@@ -0,0 +1,2551 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import warnings
+from typing import List, Union, Iterable
+from functools import partial
+from typing_extensions import Literal, overload
+
+import httpx
+
+from ... import _legacy_response
+from ...types import (
+    ThinkingConfigParam,
+    message_create_params,
+    message_count_tokens_params,
+)
+from .batches import (
+    Batches,
+    AsyncBatches,
+    BatchesWithRawResponse,
+    AsyncBatchesWithRawResponse,
+    BatchesWithStreamingResponse,
+    AsyncBatchesWithStreamingResponse,
+)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._utils import (
+    is_given,
+    required_args,
+    maybe_transform,
+    async_maybe_transform,
+)
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ..._constants import DEFAULT_TIMEOUT
+from ..._streaming import Stream, AsyncStream
+from ..._base_client import make_request_options
+from ...lib.streaming import MessageStreamManager, AsyncMessageStreamManager
+from ...types.message import Message
+from ...types.model_param import ModelParam
+from ...types.message_param import MessageParam
+from ...types.metadata_param import MetadataParam
+from ...types.text_block_param import TextBlockParam
+from ...types.tool_union_param import ToolUnionParam
+from ...types.tool_choice_param import ToolChoiceParam
+from ...types.message_tokens_count import MessageTokensCount
+from ...types.thinking_config_param import ThinkingConfigParam
+from ...types.raw_message_stream_event import RawMessageStreamEvent
+from ...types.message_count_tokens_tool_param import MessageCountTokensToolParam
+
+__all__ = ["Messages", "AsyncMessages"]
+
+
+DEPRECATED_MODELS = {
+    "claude-1.3": "November 6th, 2024",
+    "claude-1.3-100k": "November 6th, 2024",
+    "claude-instant-1.1": "November 6th, 2024",
+    "claude-instant-1.1-100k": "November 6th, 2024",
+    "claude-instant-1.2": "November 6th, 2024",
+    "claude-3-sonnet-20240229": "July 21st, 2025",
+    "claude-2.1": "July 21st, 2025",
+    "claude-2.0": "July 21st, 2025",
+}
+
+
+class Messages(SyncAPIResource):
+    @cached_property
+    def batches(self) -> Batches:
+        return Batches(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> MessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return MessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> MessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return MessagesWithStreamingResponse(self)
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Message:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        stream: Literal[True],
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Stream[RawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        stream: bool,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Message | Stream[RawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @required_args(["max_tokens", "messages", "model"], ["max_tokens", "messages", "model", "stream"])
+    def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Message | Stream[RawMessageStreamEvent]:
+        if not stream and not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
+            timeout = self._client._calculate_nonstreaming_timeout(max_tokens)
+
+        if model in DEPRECATED_MODELS:
+            warnings.warn(
+                f"The model '{model}' is deprecated and will reach end-of-life on {DEPRECATED_MODELS[model]}.\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.",
+                DeprecationWarning,
+                stacklevel=3,
+            )
+
+        return self._post(
+            "/v1/messages",
+            body=maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "stream": stream,
+                    "system": system,
+                    "temperature": temperature,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=Message,
+            stream=stream or False,
+            stream_cls=Stream[RawMessageStreamEvent],
+        )
+
+    def stream(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageStreamManager:
+        """Create a Message stream"""
+        if model in DEPRECATED_MODELS:
+            warnings.warn(
+                f"The model '{model}' is deprecated and will reach end-of-life on {DEPRECATED_MODELS[model]}.\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.",
+                DeprecationWarning,
+                stacklevel=3,
+            )
+
+        extra_headers = {
+            "X-Stainless-Stream-Helper": "messages",
+            **(extra_headers or {}),
+        }
+        make_request = partial(
+            self._post,
+            "/v1/messages",
+            body=maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "system": system,
+                    "temperature": temperature,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                    "tools": tools,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "stream": True,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=Message,
+            stream=True,
+            stream_cls=Stream[RawMessageStreamEvent],
+        )
+        return MessageStreamManager(make_request)
+
+    def count_tokens(
+        self,
+        *,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[MessageCountTokensToolParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageTokensCount:
+        """
+        Count the number of tokens in a Message.
+
+        The Token Count API can be used to count the number of tokens in a Message,
+        including tools, images, and documents, without creating it.
+
+        Learn more about token counting in our
+        [user guide](/en/docs/build-with-claude/token-counting)
+
+        Args:
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._post(
+            "/v1/messages/count_tokens",
+            body=maybe_transform(
+                {
+                    "messages": messages,
+                    "model": model,
+                    "system": system,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                },
+                message_count_tokens_params.MessageCountTokensParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageTokensCount,
+        )
+
+
+class AsyncMessages(AsyncAPIResource):
+    @cached_property
+    def batches(self) -> AsyncBatches:
+        return AsyncBatches(self._client)
+
+    @cached_property
+    def with_raw_response(self) -> AsyncMessagesWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncMessagesWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncMessagesWithStreamingResponse(self)
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Message:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        stream: Literal[True],
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncStream[RawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @overload
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        stream: bool,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Message | AsyncStream[RawMessageStreamEvent]:
+        """
+        Send a structured list of input messages with text and/or image content, and the
+        model will generate the next message in the conversation.
+
+        The Messages API can be used for either single queries or stateless multi-turn
+        conversations.
+
+        Learn more about the Messages API in our [user guide](/en/docs/initial-setup)
+
+        Args:
+          max_tokens: The maximum number of tokens to generate before stopping.
+
+              Note that our models may stop _before_ reaching this maximum. This parameter
+              only specifies the absolute maximum number of tokens to generate.
+
+              Different models have different maximum values for this parameter. See
+              [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          stream: Whether to incrementally stream the response using server-sent events.
+
+              See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+              details.
+
+          metadata: An object describing metadata about the request.
+
+          stop_sequences: Custom text sequences that will cause the model to stop generating.
+
+              Our models will normally stop when they have naturally completed their turn,
+              which will result in a response `stop_reason` of `"end_turn"`.
+
+              If you want the model to stop generating when it encounters custom strings of
+              text, you can use the `stop_sequences` parameter. If the model encounters one of
+              the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+              and the response `stop_sequence` value will contain the matched stop sequence.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          temperature: Amount of randomness injected into the response.
+
+              Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+              for analytical / multiple choice, and closer to `1.0` for creative and
+              generative tasks.
+
+              Note that even with `temperature` of `0.0`, the results will not be fully
+              deterministic.
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          top_k: Only sample from the top K options for each subsequent token.
+
+              Used to remove "long tail" low probability responses.
+              [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          top_p: Use nucleus sampling.
+
+              In nucleus sampling, we compute the cumulative distribution over all the options
+              for each subsequent token in decreasing probability order and cut it off once it
+              reaches a particular probability specified by `top_p`. You should either alter
+              `temperature` or `top_p`, but not both.
+
+              Recommended for advanced use cases only. You usually only need to use
+              `temperature`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        ...
+
+    @required_args(["max_tokens", "messages", "model"], ["max_tokens", "messages", "model", "stream"])
+    async def create(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> Message | AsyncStream[RawMessageStreamEvent]:
+        if not stream and not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
+            timeout = self._client._calculate_nonstreaming_timeout(max_tokens)
+
+        if model in DEPRECATED_MODELS:
+            warnings.warn(
+                f"The model '{model}' is deprecated and will reach end-of-life on {DEPRECATED_MODELS[model]}.\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.",
+                DeprecationWarning,
+                stacklevel=3,
+            )
+
+        return await self._post(
+            "/v1/messages",
+            body=await async_maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "stream": stream,
+                    "system": system,
+                    "temperature": temperature,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=Message,
+            stream=stream or False,
+            stream_cls=AsyncStream[RawMessageStreamEvent],
+        )
+
+    def stream(
+        self,
+        *,
+        max_tokens: int,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        metadata: MetadataParam | NotGiven = NOT_GIVEN,
+        stop_sequences: List[str] | NotGiven = NOT_GIVEN,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        temperature: float | NotGiven = NOT_GIVEN,
+        top_k: int | NotGiven = NOT_GIVEN,
+        top_p: float | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[ToolUnionParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncMessageStreamManager:
+        """Create a Message stream"""
+        if model in DEPRECATED_MODELS:
+            warnings.warn(
+                f"The model '{model}' is deprecated and will reach end-of-life on {DEPRECATED_MODELS[model]}.\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.",
+                DeprecationWarning,
+                stacklevel=3,
+            )
+
+        extra_headers = {
+            "X-Stainless-Stream-Helper": "messages",
+            **(extra_headers or {}),
+        }
+        request = self._post(
+            "/v1/messages",
+            body=maybe_transform(
+                {
+                    "max_tokens": max_tokens,
+                    "messages": messages,
+                    "model": model,
+                    "metadata": metadata,
+                    "stop_sequences": stop_sequences,
+                    "system": system,
+                    "temperature": temperature,
+                    "top_k": top_k,
+                    "top_p": top_p,
+                    "tools": tools,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "stream": True,
+                },
+                message_create_params.MessageCreateParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=Message,
+            stream=True,
+            stream_cls=AsyncStream[RawMessageStreamEvent],
+        )
+        return AsyncMessageStreamManager(request)
+
+    async def count_tokens(
+        self,
+        *,
+        messages: Iterable[MessageParam],
+        model: ModelParam,
+        system: Union[str, Iterable[TextBlockParam]] | NotGiven = NOT_GIVEN,
+        thinking: ThinkingConfigParam | NotGiven = NOT_GIVEN,
+        tool_choice: ToolChoiceParam | NotGiven = NOT_GIVEN,
+        tools: Iterable[MessageCountTokensToolParam] | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> MessageTokensCount:
+        """
+        Count the number of tokens in a Message.
+
+        The Token Count API can be used to count the number of tokens in a Message,
+        including tools, images, and documents, without creating it.
+
+        Learn more about token counting in our
+        [user guide](/en/docs/build-with-claude/token-counting)
+
+        Args:
+          messages: Input messages.
+
+              Our models are trained to operate on alternating `user` and `assistant`
+              conversational turns. When creating a new `Message`, you specify the prior
+              conversational turns with the `messages` parameter, and the model then generates
+              the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+              in your request will be combined into a single turn.
+
+              Each input message must be an object with a `role` and `content`. You can
+              specify a single `user`-role message, or you can include multiple `user` and
+              `assistant` messages.
+
+              If the final message uses the `assistant` role, the response content will
+              continue immediately from the content in that message. This can be used to
+              constrain part of the model's response.
+
+              Example with a single `user` message:
+
+              ```json
+              [{ "role": "user", "content": "Hello, Claude" }]
+              ```
+
+              Example with multiple conversational turns:
+
+              ```json
+              [
+                { "role": "user", "content": "Hello there." },
+                { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+                { "role": "user", "content": "Can you explain LLMs in plain English?" }
+              ]
+              ```
+
+              Example with a partially-filled response from Claude:
+
+              ```json
+              [
+                {
+                  "role": "user",
+                  "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+                },
+                { "role": "assistant", "content": "The best answer is (" }
+              ]
+              ```
+
+              Each input message `content` may be either a single `string` or an array of
+              content blocks, where each block has a specific `type`. Using a `string` for
+              `content` is shorthand for an array of one content block of type `"text"`. The
+              following input messages are equivalent:
+
+              ```json
+              { "role": "user", "content": "Hello, Claude" }
+              ```
+
+              ```json
+              { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+              ```
+
+              Starting with Claude 3 models, you can also send image content blocks:
+
+              ```json
+              {
+                "role": "user",
+                "content": [
+                  {
+                    "type": "image",
+                    "source": {
+                      "type": "base64",
+                      "media_type": "image/jpeg",
+                      "data": "/9j/4AAQSkZJRg..."
+                    }
+                  },
+                  { "type": "text", "text": "What is in this image?" }
+                ]
+              }
+              ```
+
+              We currently support the `base64` source type for images, and the `image/jpeg`,
+              `image/png`, `image/gif`, and `image/webp` media types.
+
+              See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+              more input examples.
+
+              Note that if you want to include a
+              [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+              the top-level `system` parameter — there is no `"system"` role for input
+              messages in the Messages API.
+
+          model: The model that will complete your prompt.\n\nSee
+              [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+              details and options.
+
+          system: System prompt.
+
+              A system prompt is a way of providing context and instructions to Claude, such
+              as specifying a particular goal or role. See our
+              [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+
+          thinking: Configuration for enabling Claude's extended thinking.
+
+              When enabled, responses include `thinking` content blocks showing Claude's
+              thinking process before the final answer. Requires a minimum budget of 1,024
+              tokens and counts towards your `max_tokens` limit.
+
+              See
+              [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+              for details.
+
+          tool_choice: How the model should use the provided tools. The model can use a specific tool,
+              any available tool, decide by itself, or not use tools at all.
+
+          tools: Definitions of tools that the model may use.
+
+              If you include `tools` in your API request, the model may return `tool_use`
+              content blocks that represent the model's use of those tools. You can then run
+              those tools using the tool input generated by the model and then optionally
+              return results back to the model using `tool_result` content blocks.
+
+              Each tool definition includes:
+
+              - `name`: Name of the tool.
+              - `description`: Optional, but strongly-recommended description of the tool.
+              - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+                tool `input` shape that the model will produce in `tool_use` output content
+                blocks.
+
+              For example, if you defined `tools` as:
+
+              ```json
+              [
+                {
+                  "name": "get_stock_price",
+                  "description": "Get the current stock price for a given ticker symbol.",
+                  "input_schema": {
+                    "type": "object",
+                    "properties": {
+                      "ticker": {
+                        "type": "string",
+                        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+                      }
+                    },
+                    "required": ["ticker"]
+                  }
+                }
+              ]
+              ```
+
+              And then asked the model "What's the S&P 500 at today?", the model might produce
+              `tool_use` content blocks in the response like this:
+
+              ```json
+              [
+                {
+                  "type": "tool_use",
+                  "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "name": "get_stock_price",
+                  "input": { "ticker": "^GSPC" }
+                }
+              ]
+              ```
+
+              You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+              input, and return the following back to the model in a subsequent `user`
+              message:
+
+              ```json
+              [
+                {
+                  "type": "tool_result",
+                  "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+                  "content": "259.75 USD"
+                }
+              ]
+              ```
+
+              Tools can be used for workflows that include running client-side tools and
+              functions, or more generally whenever you want the model to produce a particular
+              JSON structure of output.
+
+              See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return await self._post(
+            "/v1/messages/count_tokens",
+            body=await async_maybe_transform(
+                {
+                    "messages": messages,
+                    "model": model,
+                    "system": system,
+                    "thinking": thinking,
+                    "tool_choice": tool_choice,
+                    "tools": tools,
+                },
+                message_count_tokens_params.MessageCountTokensParams,
+            ),
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=MessageTokensCount,
+        )
+
+
+class MessagesWithRawResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.to_raw_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = _legacy_response.to_raw_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> BatchesWithRawResponse:
+        return BatchesWithRawResponse(self._messages.batches)
+
+
+class AsyncMessagesWithRawResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = _legacy_response.async_to_raw_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = _legacy_response.async_to_raw_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> AsyncBatchesWithRawResponse:
+        return AsyncBatchesWithRawResponse(self._messages.batches)
+
+
+class MessagesWithStreamingResponse:
+    def __init__(self, messages: Messages) -> None:
+        self._messages = messages
+
+        self.create = to_streamed_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = to_streamed_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> BatchesWithStreamingResponse:
+        return BatchesWithStreamingResponse(self._messages.batches)
+
+
+class AsyncMessagesWithStreamingResponse:
+    def __init__(self, messages: AsyncMessages) -> None:
+        self._messages = messages
+
+        self.create = async_to_streamed_response_wrapper(
+            messages.create,
+        )
+        self.count_tokens = async_to_streamed_response_wrapper(
+            messages.count_tokens,
+        )
+
+    @cached_property
+    def batches(self) -> AsyncBatchesWithStreamingResponse:
+        return AsyncBatchesWithStreamingResponse(self._messages.batches)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/resources/models.py b/.venv/lib/python3.12/site-packages/anthropic/resources/models.py
new file mode 100644
index 00000000..3469ccf9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/resources/models.py
@@ -0,0 +1,300 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from .. import _legacy_response
+from ..types import model_list_params
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from .._utils import maybe_transform
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ..pagination import SyncPage, AsyncPage
+from .._base_client import AsyncPaginator, make_request_options
+from ..types.model_info import ModelInfo
+
+__all__ = ["Models", "AsyncModels"]
+
+
+class Models(SyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> ModelsWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return ModelsWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> ModelsWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return ModelsWithStreamingResponse(self)
+
+    def retrieve(
+        self,
+        model_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> ModelInfo:
+        """
+        Get a specific model.
+
+        The Models API response can be used to determine information about a specific
+        model or resolve a model alias to a model ID.
+
+        Args:
+          model_id: Model identifier or alias.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not model_id:
+            raise ValueError(f"Expected a non-empty value for `model_id` but received {model_id!r}")
+        return self._get(
+            f"/v1/models/{model_id}",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=ModelInfo,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> SyncPage[ModelInfo]:
+        """
+        List available models.
+
+        The Models API response can be used to determine which models are available for
+        use in the API. More recently released models are listed first.
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._get_api_list(
+            "/v1/models",
+            page=SyncPage[ModelInfo],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    model_list_params.ModelListParams,
+                ),
+            ),
+            model=ModelInfo,
+        )
+
+
+class AsyncModels(AsyncAPIResource):
+    @cached_property
+    def with_raw_response(self) -> AsyncModelsWithRawResponse:
+        """
+        This property can be used as a prefix for any HTTP method call to return
+        the raw response object instead of the parsed content.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#accessing-raw-response-data-eg-headers
+        """
+        return AsyncModelsWithRawResponse(self)
+
+    @cached_property
+    def with_streaming_response(self) -> AsyncModelsWithStreamingResponse:
+        """
+        An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+        For more information, see https://www.github.com/anthropics/anthropic-sdk-python#with_streaming_response
+        """
+        return AsyncModelsWithStreamingResponse(self)
+
+    async def retrieve(
+        self,
+        model_id: str,
+        *,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> ModelInfo:
+        """
+        Get a specific model.
+
+        The Models API response can be used to determine information about a specific
+        model or resolve a model alias to a model ID.
+
+        Args:
+          model_id: Model identifier or alias.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        if not model_id:
+            raise ValueError(f"Expected a non-empty value for `model_id` but received {model_id!r}")
+        return await self._get(
+            f"/v1/models/{model_id}",
+            options=make_request_options(
+                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+            ),
+            cast_to=ModelInfo,
+        )
+
+    def list(
+        self,
+        *,
+        after_id: str | NotGiven = NOT_GIVEN,
+        before_id: str | NotGiven = NOT_GIVEN,
+        limit: int | NotGiven = NOT_GIVEN,
+        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+        # The extra values given here take precedence over values defined on the client or passed to this method.
+        extra_headers: Headers | None = None,
+        extra_query: Query | None = None,
+        extra_body: Body | None = None,
+        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+    ) -> AsyncPaginator[ModelInfo, AsyncPage[ModelInfo]]:
+        """
+        List available models.
+
+        The Models API response can be used to determine which models are available for
+        use in the API. More recently released models are listed first.
+
+        Args:
+          after_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately after this object.
+
+          before_id: ID of the object to use as a cursor for pagination. When provided, returns the
+              page of results immediately before this object.
+
+          limit: Number of items to return per page.
+
+              Defaults to `20`. Ranges from `1` to `1000`.
+
+          extra_headers: Send extra headers
+
+          extra_query: Add additional query parameters to the request
+
+          extra_body: Add additional JSON properties to the request
+
+          timeout: Override the client-level default timeout for this request, in seconds
+        """
+        return self._get_api_list(
+            "/v1/models",
+            page=AsyncPage[ModelInfo],
+            options=make_request_options(
+                extra_headers=extra_headers,
+                extra_query=extra_query,
+                extra_body=extra_body,
+                timeout=timeout,
+                query=maybe_transform(
+                    {
+                        "after_id": after_id,
+                        "before_id": before_id,
+                        "limit": limit,
+                    },
+                    model_list_params.ModelListParams,
+                ),
+            ),
+            model=ModelInfo,
+        )
+
+
+class ModelsWithRawResponse:
+    def __init__(self, models: Models) -> None:
+        self._models = models
+
+        self.retrieve = _legacy_response.to_raw_response_wrapper(
+            models.retrieve,
+        )
+        self.list = _legacy_response.to_raw_response_wrapper(
+            models.list,
+        )
+
+
+class AsyncModelsWithRawResponse:
+    def __init__(self, models: AsyncModels) -> None:
+        self._models = models
+
+        self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+            models.retrieve,
+        )
+        self.list = _legacy_response.async_to_raw_response_wrapper(
+            models.list,
+        )
+
+
+class ModelsWithStreamingResponse:
+    def __init__(self, models: Models) -> None:
+        self._models = models
+
+        self.retrieve = to_streamed_response_wrapper(
+            models.retrieve,
+        )
+        self.list = to_streamed_response_wrapper(
+            models.list,
+        )
+
+
+class AsyncModelsWithStreamingResponse:
+    def __init__(self, models: AsyncModels) -> None:
+        self._models = models
+
+        self.retrieve = async_to_streamed_response_wrapper(
+            models.retrieve,
+        )
+        self.list = async_to_streamed_response_wrapper(
+            models.list,
+        )
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/types/__init__.py
new file mode 100644
index 00000000..94196102
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/__init__.py
@@ -0,0 +1,107 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .model import Model as Model
+from .usage import Usage as Usage
+from .shared import (
+    ErrorObject as ErrorObject,
+    BillingError as BillingError,
+    ErrorResponse as ErrorResponse,
+    NotFoundError as NotFoundError,
+    APIErrorObject as APIErrorObject,
+    RateLimitError as RateLimitError,
+    OverloadedError as OverloadedError,
+    PermissionError as PermissionError,
+    AuthenticationError as AuthenticationError,
+    GatewayTimeoutError as GatewayTimeoutError,
+    InvalidRequestError as InvalidRequestError,
+)
+from .message import Message as Message
+from .beta_error import BetaError as BetaError
+from .completion import Completion as Completion
+from .model_info import ModelInfo as ModelInfo
+from .text_block import TextBlock as TextBlock
+from .text_delta import TextDelta as TextDelta
+from .tool_param import ToolParam as ToolParam
+from .model_param import ModelParam as ModelParam
+from .content_block import ContentBlock as ContentBlock
+from .message_param import MessageParam as MessageParam
+from .text_citation import TextCitation as TextCitation
+from .beta_api_error import BetaAPIError as BetaAPIError
+from .metadata_param import MetadataParam as MetadataParam
+from .thinking_block import ThinkingBlock as ThinkingBlock
+from .thinking_delta import ThinkingDelta as ThinkingDelta
+from .tool_use_block import ToolUseBlock as ToolUseBlock
+from .citations_delta import CitationsDelta as CitationsDelta
+from .signature_delta import SignatureDelta as SignatureDelta
+from .input_json_delta import InputJSONDelta as InputJSONDelta
+from .text_block_param import TextBlockParam as TextBlockParam
+from .tool_union_param import ToolUnionParam as ToolUnionParam
+from .image_block_param import ImageBlockParam as ImageBlockParam
+from .model_list_params import ModelListParams as ModelListParams
+from .tool_choice_param import ToolChoiceParam as ToolChoiceParam
+from .beta_billing_error import BetaBillingError as BetaBillingError
+from .message_stop_event import MessageStopEvent as MessageStopEvent
+from .beta_error_response import BetaErrorResponse as BetaErrorResponse
+from .content_block_param import ContentBlockParam as ContentBlockParam
+from .message_delta_event import MessageDeltaEvent as MessageDeltaEvent
+from .message_delta_usage import MessageDeltaUsage as MessageDeltaUsage
+from .message_start_event import MessageStartEvent as MessageStartEvent
+from .text_citation_param import TextCitationParam as TextCitationParam
+from .anthropic_beta_param import AnthropicBetaParam as AnthropicBetaParam
+from .beta_not_found_error import BetaNotFoundError as BetaNotFoundError
+from .document_block_param import DocumentBlockParam as DocumentBlockParam
+from .message_stream_event import MessageStreamEvent as MessageStreamEvent
+from .message_tokens_count import MessageTokensCount as MessageTokensCount
+from .thinking_block_param import ThinkingBlockParam as ThinkingBlockParam
+from .tool_use_block_param import ToolUseBlockParam as ToolUseBlockParam
+from .url_pdf_source_param import URLPDFSourceParam as URLPDFSourceParam
+from .beta_overloaded_error import BetaOverloadedError as BetaOverloadedError
+from .beta_permission_error import BetaPermissionError as BetaPermissionError
+from .beta_rate_limit_error import BetaRateLimitError as BetaRateLimitError
+from .message_create_params import MessageCreateParams as MessageCreateParams
+from .thinking_config_param import ThinkingConfigParam as ThinkingConfigParam
+from .tool_choice_any_param import ToolChoiceAnyParam as ToolChoiceAnyParam
+from .citation_char_location import CitationCharLocation as CitationCharLocation
+from .citation_page_location import CitationPageLocation as CitationPageLocation
+from .citations_config_param import CitationsConfigParam as CitationsConfigParam
+from .raw_message_stop_event import RawMessageStopEvent as RawMessageStopEvent
+from .tool_choice_auto_param import ToolChoiceAutoParam as ToolChoiceAutoParam
+from .tool_choice_none_param import ToolChoiceNoneParam as ToolChoiceNoneParam
+from .tool_choice_tool_param import ToolChoiceToolParam as ToolChoiceToolParam
+from .url_image_source_param import URLImageSourceParam as URLImageSourceParam
+from .base64_pdf_source_param import Base64PDFSourceParam as Base64PDFSourceParam
+from .plain_text_source_param import PlainTextSourceParam as PlainTextSourceParam
+from .raw_message_delta_event import RawMessageDeltaEvent as RawMessageDeltaEvent
+from .raw_message_start_event import RawMessageStartEvent as RawMessageStartEvent
+from .redacted_thinking_block import RedactedThinkingBlock as RedactedThinkingBlock
+from .tool_result_block_param import ToolResultBlockParam as ToolResultBlockParam
+from .completion_create_params import CompletionCreateParams as CompletionCreateParams
+from .content_block_stop_event import ContentBlockStopEvent as ContentBlockStopEvent
+from .raw_message_stream_event import RawMessageStreamEvent as RawMessageStreamEvent
+from .tool_bash_20250124_param import ToolBash20250124Param as ToolBash20250124Param
+from .base64_image_source_param import Base64ImageSourceParam as Base64ImageSourceParam
+from .beta_authentication_error import BetaAuthenticationError as BetaAuthenticationError
+from .content_block_delta_event import ContentBlockDeltaEvent as ContentBlockDeltaEvent
+from .content_block_start_event import ContentBlockStartEvent as ContentBlockStartEvent
+from .beta_gateway_timeout_error import BetaGatewayTimeoutError as BetaGatewayTimeoutError
+from .beta_invalid_request_error import BetaInvalidRequestError as BetaInvalidRequestError
+from .content_block_source_param import ContentBlockSourceParam as ContentBlockSourceParam
+from .message_count_tokens_params import MessageCountTokensParams as MessageCountTokensParams
+from .citation_char_location_param import CitationCharLocationParam as CitationCharLocationParam
+from .citation_page_location_param import CitationPageLocationParam as CitationPageLocationParam
+from .raw_content_block_stop_event import RawContentBlockStopEvent as RawContentBlockStopEvent
+from .cache_control_ephemeral_param import CacheControlEphemeralParam as CacheControlEphemeralParam
+from .raw_content_block_delta_event import RawContentBlockDeltaEvent as RawContentBlockDeltaEvent
+from .raw_content_block_start_event import RawContentBlockStartEvent as RawContentBlockStartEvent
+from .redacted_thinking_block_param import RedactedThinkingBlockParam as RedactedThinkingBlockParam
+from .thinking_config_enabled_param import ThinkingConfigEnabledParam as ThinkingConfigEnabledParam
+from .thinking_config_disabled_param import ThinkingConfigDisabledParam as ThinkingConfigDisabledParam
+from .citation_content_block_location import CitationContentBlockLocation as CitationContentBlockLocation
+from .message_count_tokens_tool_param import MessageCountTokensToolParam as MessageCountTokensToolParam
+from .tool_text_editor_20250124_param import ToolTextEditor20250124Param as ToolTextEditor20250124Param
+from .content_block_source_content_param import ContentBlockSourceContentParam as ContentBlockSourceContentParam
+from .citation_content_block_location_param import (
+    CitationContentBlockLocationParam as CitationContentBlockLocationParam,
+)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/anthropic_beta_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/anthropic_beta_param.py
new file mode 100644
index 00000000..ff5fdffd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/anthropic_beta_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["AnthropicBetaParam"]
+
+AnthropicBetaParam: TypeAlias = Union[
+    str,
+    Literal[
+        "message-batches-2024-09-24",
+        "prompt-caching-2024-07-31",
+        "computer-use-2024-10-22",
+        "computer-use-2025-01-24",
+        "pdfs-2024-09-25",
+        "token-counting-2024-11-01",
+        "token-efficient-tools-2025-02-19",
+        "output-128k-2025-02-19",
+    ],
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/base64_image_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/base64_image_source_param.py
new file mode 100644
index 00000000..93fdb9d1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/base64_image_source_param.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._types import Base64FileInput
+from .._utils import PropertyInfo
+from .._models import set_pydantic_config
+
+__all__ = ["Base64ImageSourceParam"]
+
+
+class Base64ImageSourceParam(TypedDict, total=False):
+    data: Required[Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")]]
+
+    media_type: Required[Literal["image/jpeg", "image/png", "image/gif", "image/webp"]]
+
+    type: Required[Literal["base64"]]
+
+
+set_pydantic_config(Base64ImageSourceParam, {"arbitrary_types_allowed": True})
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/base64_pdf_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/base64_pdf_source_param.py
new file mode 100644
index 00000000..ac247a19
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/base64_pdf_source_param.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._types import Base64FileInput
+from .._utils import PropertyInfo
+from .._models import set_pydantic_config
+
+__all__ = ["Base64PDFSourceParam"]
+
+
+class Base64PDFSourceParam(TypedDict, total=False):
+    data: Required[Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")]]
+
+    media_type: Required[Literal["application/pdf"]]
+
+    type: Required[Literal["base64"]]
+
+
+set_pydantic_config(Base64PDFSourceParam, {"arbitrary_types_allowed": True})
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/__init__.py
new file mode 100644
index 00000000..916b0ab6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/__init__.py
@@ -0,0 +1,76 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .beta_usage import BetaUsage as BetaUsage
+from .beta_message import BetaMessage as BetaMessage
+from .beta_model_info import BetaModelInfo as BetaModelInfo
+from .beta_text_block import BetaTextBlock as BetaTextBlock
+from .beta_text_delta import BetaTextDelta as BetaTextDelta
+from .beta_tool_param import BetaToolParam as BetaToolParam
+from .model_list_params import ModelListParams as ModelListParams
+from .beta_content_block import BetaContentBlock as BetaContentBlock
+from .beta_message_param import BetaMessageParam as BetaMessageParam
+from .beta_text_citation import BetaTextCitation as BetaTextCitation
+from .beta_metadata_param import BetaMetadataParam as BetaMetadataParam
+from .beta_thinking_block import BetaThinkingBlock as BetaThinkingBlock
+from .beta_thinking_delta import BetaThinkingDelta as BetaThinkingDelta
+from .beta_tool_use_block import BetaToolUseBlock as BetaToolUseBlock
+from .beta_citations_delta import BetaCitationsDelta as BetaCitationsDelta
+from .beta_signature_delta import BetaSignatureDelta as BetaSignatureDelta
+from .beta_input_json_delta import BetaInputJSONDelta as BetaInputJSONDelta
+from .beta_text_block_param import BetaTextBlockParam as BetaTextBlockParam
+from .beta_tool_union_param import BetaToolUnionParam as BetaToolUnionParam
+from .message_create_params import MessageCreateParams as MessageCreateParams
+from .beta_image_block_param import BetaImageBlockParam as BetaImageBlockParam
+from .beta_tool_choice_param import BetaToolChoiceParam as BetaToolChoiceParam
+from .beta_content_block_param import BetaContentBlockParam as BetaContentBlockParam
+from .beta_message_delta_usage import BetaMessageDeltaUsage as BetaMessageDeltaUsage
+from .beta_text_citation_param import BetaTextCitationParam as BetaTextCitationParam
+from .beta_message_tokens_count import BetaMessageTokensCount as BetaMessageTokensCount
+from .beta_thinking_block_param import BetaThinkingBlockParam as BetaThinkingBlockParam
+from .beta_tool_use_block_param import BetaToolUseBlockParam as BetaToolUseBlockParam
+from .beta_url_pdf_source_param import BetaURLPDFSourceParam as BetaURLPDFSourceParam
+from .beta_thinking_config_param import BetaThinkingConfigParam as BetaThinkingConfigParam
+from .beta_tool_choice_any_param import BetaToolChoiceAnyParam as BetaToolChoiceAnyParam
+from .beta_base64_pdf_block_param import BetaBase64PDFBlockParam as BetaBase64PDFBlockParam
+from .beta_citation_char_location import BetaCitationCharLocation as BetaCitationCharLocation
+from .beta_citation_page_location import BetaCitationPageLocation as BetaCitationPageLocation
+from .beta_citations_config_param import BetaCitationsConfigParam as BetaCitationsConfigParam
+from .beta_raw_message_stop_event import BetaRawMessageStopEvent as BetaRawMessageStopEvent
+from .beta_tool_choice_auto_param import BetaToolChoiceAutoParam as BetaToolChoiceAutoParam
+from .beta_tool_choice_none_param import BetaToolChoiceNoneParam as BetaToolChoiceNoneParam
+from .beta_tool_choice_tool_param import BetaToolChoiceToolParam as BetaToolChoiceToolParam
+from .beta_url_image_source_param import BetaURLImageSourceParam as BetaURLImageSourceParam
+from .message_count_tokens_params import MessageCountTokensParams as MessageCountTokensParams
+from .beta_base64_pdf_source_param import BetaBase64PDFSourceParam as BetaBase64PDFSourceParam
+from .beta_plain_text_source_param import BetaPlainTextSourceParam as BetaPlainTextSourceParam
+from .beta_raw_message_delta_event import BetaRawMessageDeltaEvent as BetaRawMessageDeltaEvent
+from .beta_raw_message_start_event import BetaRawMessageStartEvent as BetaRawMessageStartEvent
+from .beta_redacted_thinking_block import BetaRedactedThinkingBlock as BetaRedactedThinkingBlock
+from .beta_tool_result_block_param import BetaToolResultBlockParam as BetaToolResultBlockParam
+from .beta_raw_message_stream_event import BetaRawMessageStreamEvent as BetaRawMessageStreamEvent
+from .beta_tool_bash_20241022_param import BetaToolBash20241022Param as BetaToolBash20241022Param
+from .beta_tool_bash_20250124_param import BetaToolBash20250124Param as BetaToolBash20250124Param
+from .beta_base64_image_source_param import BetaBase64ImageSourceParam as BetaBase64ImageSourceParam
+from .beta_content_block_source_param import BetaContentBlockSourceParam as BetaContentBlockSourceParam
+from .beta_citation_char_location_param import BetaCitationCharLocationParam as BetaCitationCharLocationParam
+from .beta_citation_page_location_param import BetaCitationPageLocationParam as BetaCitationPageLocationParam
+from .beta_raw_content_block_stop_event import BetaRawContentBlockStopEvent as BetaRawContentBlockStopEvent
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam as BetaCacheControlEphemeralParam
+from .beta_raw_content_block_delta_event import BetaRawContentBlockDeltaEvent as BetaRawContentBlockDeltaEvent
+from .beta_raw_content_block_start_event import BetaRawContentBlockStartEvent as BetaRawContentBlockStartEvent
+from .beta_redacted_thinking_block_param import BetaRedactedThinkingBlockParam as BetaRedactedThinkingBlockParam
+from .beta_thinking_config_enabled_param import BetaThinkingConfigEnabledParam as BetaThinkingConfigEnabledParam
+from .beta_thinking_config_disabled_param import BetaThinkingConfigDisabledParam as BetaThinkingConfigDisabledParam
+from .beta_citation_content_block_location import BetaCitationContentBlockLocation as BetaCitationContentBlockLocation
+from .beta_tool_text_editor_20241022_param import BetaToolTextEditor20241022Param as BetaToolTextEditor20241022Param
+from .beta_tool_text_editor_20250124_param import BetaToolTextEditor20250124Param as BetaToolTextEditor20250124Param
+from .beta_tool_computer_use_20241022_param import BetaToolComputerUse20241022Param as BetaToolComputerUse20241022Param
+from .beta_tool_computer_use_20250124_param import BetaToolComputerUse20250124Param as BetaToolComputerUse20250124Param
+from .beta_content_block_source_content_param import (
+    BetaContentBlockSourceContentParam as BetaContentBlockSourceContentParam,
+)
+from .beta_citation_content_block_location_param import (
+    BetaCitationContentBlockLocationParam as BetaCitationContentBlockLocationParam,
+)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_image_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_image_source_param.py
new file mode 100644
index 00000000..8f13ce38
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_image_source_param.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from ..._types import Base64FileInput
+from ..._utils import PropertyInfo
+from ..._models import set_pydantic_config
+
+__all__ = ["BetaBase64ImageSourceParam"]
+
+
+class BetaBase64ImageSourceParam(TypedDict, total=False):
+    data: Required[Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")]]
+
+    media_type: Required[Literal["image/jpeg", "image/png", "image/gif", "image/webp"]]
+
+    type: Required[Literal["base64"]]
+
+
+set_pydantic_config(BetaBase64ImageSourceParam, {"arbitrary_types_allowed": True})
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_block_param.py
new file mode 100644
index 00000000..16f51a9d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_block_param.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .beta_url_pdf_source_param import BetaURLPDFSourceParam
+from .beta_citations_config_param import BetaCitationsConfigParam
+from .beta_base64_pdf_source_param import BetaBase64PDFSourceParam
+from .beta_plain_text_source_param import BetaPlainTextSourceParam
+from .beta_content_block_source_param import BetaContentBlockSourceParam
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaBase64PDFBlockParam", "Source"]
+
+Source: TypeAlias = Union[
+    BetaBase64PDFSourceParam, BetaPlainTextSourceParam, BetaContentBlockSourceParam, BetaURLPDFSourceParam
+]
+
+
+class BetaBase64PDFBlockParam(TypedDict, total=False):
+    source: Required[Source]
+
+    type: Required[Literal["document"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
+
+    citations: BetaCitationsConfigParam
+
+    context: Optional[str]
+
+    title: Optional[str]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_source_param.py
new file mode 100644
index 00000000..1137c957
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_base64_pdf_source_param.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from ..._types import Base64FileInput
+from ..._utils import PropertyInfo
+from ..._models import set_pydantic_config
+
+__all__ = ["BetaBase64PDFSourceParam"]
+
+
+class BetaBase64PDFSourceParam(TypedDict, total=False):
+    data: Required[Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")]]
+
+    media_type: Required[Literal["application/pdf"]]
+
+    type: Required[Literal["base64"]]
+
+
+set_pydantic_config(BetaBase64PDFSourceParam, {"arbitrary_types_allowed": True})
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_cache_control_ephemeral_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_cache_control_ephemeral_param.py
new file mode 100644
index 00000000..540d769d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_cache_control_ephemeral_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaCacheControlEphemeralParam"]
+
+
+class BetaCacheControlEphemeralParam(TypedDict, total=False):
+    type: Required[Literal["ephemeral"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location.py
new file mode 100644
index 00000000..2109949a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaCitationCharLocation"]
+
+
+class BetaCitationCharLocation(BaseModel):
+    cited_text: str
+
+    document_index: int
+
+    document_title: Optional[str] = None
+
+    end_char_index: int
+
+    start_char_index: int
+
+    type: Literal["char_location"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location_param.py
new file mode 100644
index 00000000..8c09f5a7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_char_location_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaCitationCharLocationParam"]
+
+
+class BetaCitationCharLocationParam(TypedDict, total=False):
+    cited_text: Required[str]
+
+    document_index: Required[int]
+
+    document_title: Required[Optional[str]]
+
+    end_char_index: Required[int]
+
+    start_char_index: Required[int]
+
+    type: Required[Literal["char_location"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location.py
new file mode 100644
index 00000000..8fde76f9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaCitationContentBlockLocation"]
+
+
+class BetaCitationContentBlockLocation(BaseModel):
+    cited_text: str
+
+    document_index: int
+
+    document_title: Optional[str] = None
+
+    end_block_index: int
+
+    start_block_index: int
+
+    type: Literal["content_block_location"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location_param.py
new file mode 100644
index 00000000..9e378a78
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_content_block_location_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaCitationContentBlockLocationParam"]
+
+
+class BetaCitationContentBlockLocationParam(TypedDict, total=False):
+    cited_text: Required[str]
+
+    document_index: Required[int]
+
+    document_title: Required[Optional[str]]
+
+    end_block_index: Required[int]
+
+    start_block_index: Required[int]
+
+    type: Required[Literal["content_block_location"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location.py
new file mode 100644
index 00000000..9e6f60dd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaCitationPageLocation"]
+
+
+class BetaCitationPageLocation(BaseModel):
+    cited_text: str
+
+    document_index: int
+
+    document_title: Optional[str] = None
+
+    end_page_number: int
+
+    start_page_number: int
+
+    type: Literal["page_location"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location_param.py
new file mode 100644
index 00000000..60e5b1c2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citation_page_location_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaCitationPageLocationParam"]
+
+
+class BetaCitationPageLocationParam(TypedDict, total=False):
+    cited_text: Required[str]
+
+    document_index: Required[int]
+
+    document_title: Required[Optional[str]]
+
+    end_page_number: Required[int]
+
+    start_page_number: Required[int]
+
+    type: Required[Literal["page_location"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_config_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_config_param.py
new file mode 100644
index 00000000..409cfde7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_config_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["BetaCitationsConfigParam"]
+
+
+class BetaCitationsConfigParam(TypedDict, total=False):
+    enabled: bool
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_delta.py
new file mode 100644
index 00000000..2c6c02b2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_citations_delta.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from ..._models import BaseModel
+from .beta_citation_char_location import BetaCitationCharLocation
+from .beta_citation_page_location import BetaCitationPageLocation
+from .beta_citation_content_block_location import BetaCitationContentBlockLocation
+
+__all__ = ["BetaCitationsDelta", "Citation"]
+
+Citation: TypeAlias = Annotated[
+    Union[BetaCitationCharLocation, BetaCitationPageLocation, BetaCitationContentBlockLocation],
+    PropertyInfo(discriminator="type"),
+]
+
+
+class BetaCitationsDelta(BaseModel):
+    citation: Citation
+
+    type: Literal["citations_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block.py
new file mode 100644
index 00000000..7cf9736e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from .beta_text_block import BetaTextBlock
+from .beta_thinking_block import BetaThinkingBlock
+from .beta_tool_use_block import BetaToolUseBlock
+from .beta_redacted_thinking_block import BetaRedactedThinkingBlock
+
+__all__ = ["BetaContentBlock"]
+
+BetaContentBlock: TypeAlias = Annotated[
+    Union[BetaTextBlock, BetaToolUseBlock, BetaThinkingBlock, BetaRedactedThinkingBlock],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_param.py
new file mode 100644
index 00000000..1768f321
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_param.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .beta_text_block_param import BetaTextBlockParam
+from .beta_image_block_param import BetaImageBlockParam
+from .beta_thinking_block_param import BetaThinkingBlockParam
+from .beta_tool_use_block_param import BetaToolUseBlockParam
+from .beta_base64_pdf_block_param import BetaBase64PDFBlockParam
+from .beta_tool_result_block_param import BetaToolResultBlockParam
+from .beta_redacted_thinking_block_param import BetaRedactedThinkingBlockParam
+
+__all__ = ["BetaContentBlockParam"]
+
+BetaContentBlockParam: TypeAlias = Union[
+    BetaTextBlockParam,
+    BetaImageBlockParam,
+    BetaToolUseBlockParam,
+    BetaToolResultBlockParam,
+    BetaBase64PDFBlockParam,
+    BetaThinkingBlockParam,
+    BetaRedactedThinkingBlockParam,
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_content_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_content_param.py
new file mode 100644
index 00000000..bc13b146
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_content_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .beta_text_block_param import BetaTextBlockParam
+from .beta_image_block_param import BetaImageBlockParam
+
+__all__ = ["BetaContentBlockSourceContentParam"]
+
+BetaContentBlockSourceContentParam: TypeAlias = Union[BetaTextBlockParam, BetaImageBlockParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_param.py
new file mode 100644
index 00000000..512cf0db
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_content_block_source_param.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_content_block_source_content_param import BetaContentBlockSourceContentParam
+
+__all__ = ["BetaContentBlockSourceParam"]
+
+
+class BetaContentBlockSourceParam(TypedDict, total=False):
+    content: Required[Union[str, Iterable[BetaContentBlockSourceContentParam]]]
+
+    type: Required[Literal["content"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_image_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_image_block_param.py
new file mode 100644
index 00000000..ddb9d4c0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_image_block_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .beta_url_image_source_param import BetaURLImageSourceParam
+from .beta_base64_image_source_param import BetaBase64ImageSourceParam
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaImageBlockParam", "Source"]
+
+Source: TypeAlias = Union[BetaBase64ImageSourceParam, BetaURLImageSourceParam]
+
+
+class BetaImageBlockParam(TypedDict, total=False):
+    source: Required[Source]
+
+    type: Required[Literal["image"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_input_json_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_input_json_delta.py
new file mode 100644
index 00000000..a5f9cbea
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_input_json_delta.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaInputJSONDelta"]
+
+
+class BetaInputJSONDelta(BaseModel):
+    partial_json: str
+
+    type: Literal["input_json_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message.py
new file mode 100644
index 00000000..a4d6cdec
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message.py
@@ -0,0 +1,112 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from ..model import Model
+from ..._models import BaseModel
+from .beta_usage import BetaUsage
+from .beta_content_block import BetaContentBlock, BetaContentBlock as BetaContentBlock
+
+__all__ = ["BetaMessage"]
+
+
+class BetaMessage(BaseModel):
+    id: str
+    """Unique object identifier.
+
+    The format and length of IDs may change over time.
+    """
+
+    content: List[BetaContentBlock]
+    """Content generated by the model.
+
+    This is an array of content blocks, each of which has a `type` that determines
+    its shape.
+
+    Example:
+
+    ```json
+    [{ "type": "text", "text": "Hi, I'm Claude." }]
+    ```
+
+    If the request input `messages` ended with an `assistant` turn, then the
+    response `content` will continue directly from that last turn. You can use this
+    to constrain the model's output.
+
+    For example, if the input `messages` were:
+
+    ```json
+    [
+      {
+        "role": "user",
+        "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+      },
+      { "role": "assistant", "content": "The best answer is (" }
+    ]
+    ```
+
+    Then the response `content` might be:
+
+    ```json
+    [{ "type": "text", "text": "B)" }]
+    ```
+    """
+
+    model: Model
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    role: Literal["assistant"]
+    """Conversational role of the generated message.
+
+    This will always be `"assistant"`.
+    """
+
+    stop_reason: Optional[Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]] = None
+    """The reason that we stopped.
+
+    This may be one the following values:
+
+    - `"end_turn"`: the model reached a natural stopping point
+    - `"max_tokens"`: we exceeded the requested `max_tokens` or the model's maximum
+    - `"stop_sequence"`: one of your provided custom `stop_sequences` was generated
+    - `"tool_use"`: the model invoked one or more tools
+
+    In non-streaming mode this value is always non-null. In streaming mode, it is
+    null in the `message_start` event and non-null otherwise.
+    """
+
+    stop_sequence: Optional[str] = None
+    """Which custom stop sequence was generated, if any.
+
+    This value will be a non-null string if one of your custom stop sequences was
+    generated.
+    """
+
+    type: Literal["message"]
+    """Object type.
+
+    For Messages, this is always `"message"`.
+    """
+
+    usage: BetaUsage
+    """Billing and rate-limit usage.
+
+    Anthropic's API bills and rate-limits by token counts, as tokens represent the
+    underlying cost to our systems.
+
+    Under the hood, the API transforms requests into a format suitable for the
+    model. The model's output then goes through a parsing stage before becoming an
+    API response. As a result, the token counts in `usage` will not match one-to-one
+    with the exact visible content of an API request or response.
+
+    For example, `output_tokens` will be non-zero, even for an empty string response
+    from Claude.
+
+    Total input tokens in a request is the summation of `input_tokens`,
+    `cache_creation_input_tokens`, and `cache_read_input_tokens`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_delta_usage.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_delta_usage.py
new file mode 100644
index 00000000..cc681911
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_delta_usage.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from ..._models import BaseModel
+
+__all__ = ["BetaMessageDeltaUsage"]
+
+
+class BetaMessageDeltaUsage(BaseModel):
+    output_tokens: int
+    """The cumulative number of output tokens which were used."""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_param.py
new file mode 100644
index 00000000..b41e56d3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_param.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_content_block_param import BetaContentBlockParam
+
+__all__ = ["BetaMessageParam"]
+
+
+class BetaMessageParam(TypedDict, total=False):
+    content: Required[Union[str, Iterable[BetaContentBlockParam]]]
+
+    role: Required[Literal["user", "assistant"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_tokens_count.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_tokens_count.py
new file mode 100644
index 00000000..e11daee7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_message_tokens_count.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from ..._models import BaseModel
+
+__all__ = ["BetaMessageTokensCount"]
+
+
+class BetaMessageTokensCount(BaseModel):
+    input_tokens: int
+    """
+    The total number of tokens across the provided list of messages, system prompt,
+    and tools.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_metadata_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_metadata_param.py
new file mode 100644
index 00000000..8ccda216
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_metadata_param.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import TypedDict
+
+__all__ = ["BetaMetadataParam"]
+
+
+class BetaMetadataParam(TypedDict, total=False):
+    user_id: Optional[str]
+    """An external identifier for the user who is associated with the request.
+
+    This should be a uuid, hash value, or other opaque identifier. Anthropic may use
+    this id to help detect abuse. Do not include any identifying information such as
+    name, email address, or phone number.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_model_info.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_model_info.py
new file mode 100644
index 00000000..6ea50d9f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_model_info.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaModelInfo"]
+
+
+class BetaModelInfo(BaseModel):
+    id: str
+    """Unique model identifier."""
+
+    created_at: datetime
+    """RFC 3339 datetime string representing the time at which the model was released.
+
+    May be set to an epoch value if the release date is unknown.
+    """
+
+    display_name: str
+    """A human-readable name for the model."""
+
+    type: Literal["model"]
+    """Object type.
+
+    For Models, this is always `"model"`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_plain_text_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_plain_text_source_param.py
new file mode 100644
index 00000000..187a2386
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_plain_text_source_param.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaPlainTextSourceParam"]
+
+
+class BetaPlainTextSourceParam(TypedDict, total=False):
+    data: Required[str]
+
+    media_type: Required[Literal["text/plain"]]
+
+    type: Required[Literal["text"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_delta_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_delta_event.py
new file mode 100644
index 00000000..cd50f289
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_delta_event.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from ..._models import BaseModel
+from .beta_text_delta import BetaTextDelta
+from .beta_thinking_delta import BetaThinkingDelta
+from .beta_citations_delta import BetaCitationsDelta
+from .beta_signature_delta import BetaSignatureDelta
+from .beta_input_json_delta import BetaInputJSONDelta
+
+__all__ = ["BetaRawContentBlockDeltaEvent", "Delta"]
+
+Delta: TypeAlias = Annotated[
+    Union[BetaTextDelta, BetaInputJSONDelta, BetaCitationsDelta, BetaThinkingDelta, BetaSignatureDelta],
+    PropertyInfo(discriminator="type"),
+]
+
+
+class BetaRawContentBlockDeltaEvent(BaseModel):
+    delta: Delta
+
+    index: int
+
+    type: Literal["content_block_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_start_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_start_event.py
new file mode 100644
index 00000000..086c216c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_start_event.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from ..._models import BaseModel
+from .beta_text_block import BetaTextBlock
+from .beta_thinking_block import BetaThinkingBlock
+from .beta_tool_use_block import BetaToolUseBlock
+from .beta_redacted_thinking_block import BetaRedactedThinkingBlock
+
+__all__ = ["BetaRawContentBlockStartEvent", "ContentBlock"]
+
+ContentBlock: TypeAlias = Annotated[
+    Union[BetaTextBlock, BetaToolUseBlock, BetaThinkingBlock, BetaRedactedThinkingBlock],
+    PropertyInfo(discriminator="type"),
+]
+
+
+class BetaRawContentBlockStartEvent(BaseModel):
+    content_block: ContentBlock
+
+    index: int
+
+    type: Literal["content_block_start"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_stop_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_stop_event.py
new file mode 100644
index 00000000..d8551860
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_content_block_stop_event.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaRawContentBlockStopEvent"]
+
+
+class BetaRawContentBlockStopEvent(BaseModel):
+    index: int
+
+    type: Literal["content_block_stop"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_delta_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_delta_event.py
new file mode 100644
index 00000000..525fd10c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_delta_event.py
@@ -0,0 +1,39 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+from .beta_message_delta_usage import BetaMessageDeltaUsage
+
+__all__ = ["BetaRawMessageDeltaEvent", "Delta"]
+
+
+class Delta(BaseModel):
+    stop_reason: Optional[Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]] = None
+
+    stop_sequence: Optional[str] = None
+
+
+class BetaRawMessageDeltaEvent(BaseModel):
+    delta: Delta
+
+    type: Literal["message_delta"]
+
+    usage: BetaMessageDeltaUsage
+    """Billing and rate-limit usage.
+
+    Anthropic's API bills and rate-limits by token counts, as tokens represent the
+    underlying cost to our systems.
+
+    Under the hood, the API transforms requests into a format suitable for the
+    model. The model's output then goes through a parsing stage before becoming an
+    API response. As a result, the token counts in `usage` will not match one-to-one
+    with the exact visible content of an API request or response.
+
+    For example, `output_tokens` will be non-zero, even for an empty string response
+    from Claude.
+
+    Total input tokens in a request is the summation of `input_tokens`,
+    `cache_creation_input_tokens`, and `cache_read_input_tokens`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_start_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_start_event.py
new file mode 100644
index 00000000..9bb16f94
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_start_event.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+from .beta_message import BetaMessage
+
+__all__ = ["BetaRawMessageStartEvent"]
+
+
+class BetaRawMessageStartEvent(BaseModel):
+    message: BetaMessage
+
+    type: Literal["message_start"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stop_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stop_event.py
new file mode 100644
index 00000000..dff33cde
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stop_event.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaRawMessageStopEvent"]
+
+
+class BetaRawMessageStopEvent(BaseModel):
+    type: Literal["message_stop"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stream_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stream_event.py
new file mode 100644
index 00000000..00ffd7c1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_raw_message_stream_event.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from .beta_raw_message_stop_event import BetaRawMessageStopEvent
+from .beta_raw_message_delta_event import BetaRawMessageDeltaEvent
+from .beta_raw_message_start_event import BetaRawMessageStartEvent
+from .beta_raw_content_block_stop_event import BetaRawContentBlockStopEvent
+from .beta_raw_content_block_delta_event import BetaRawContentBlockDeltaEvent
+from .beta_raw_content_block_start_event import BetaRawContentBlockStartEvent
+
+__all__ = ["BetaRawMessageStreamEvent"]
+
+BetaRawMessageStreamEvent: TypeAlias = Annotated[
+    Union[
+        BetaRawMessageStartEvent,
+        BetaRawMessageDeltaEvent,
+        BetaRawMessageStopEvent,
+        BetaRawContentBlockStartEvent,
+        BetaRawContentBlockDeltaEvent,
+        BetaRawContentBlockStopEvent,
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block.py
new file mode 100644
index 00000000..b27bd933
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaRedactedThinkingBlock"]
+
+
+class BetaRedactedThinkingBlock(BaseModel):
+    data: str
+
+    type: Literal["redacted_thinking"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block_param.py
new file mode 100644
index 00000000..cc7d870f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_redacted_thinking_block_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaRedactedThinkingBlockParam"]
+
+
+class BetaRedactedThinkingBlockParam(TypedDict, total=False):
+    data: Required[str]
+
+    type: Required[Literal["redacted_thinking"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_signature_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_signature_delta.py
new file mode 100644
index 00000000..a3586826
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_signature_delta.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaSignatureDelta"]
+
+
+class BetaSignatureDelta(BaseModel):
+    signature: str
+
+    type: Literal["signature_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block.py
new file mode 100644
index 00000000..f6374b41
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+from .beta_text_citation import BetaTextCitation
+
+__all__ = ["BetaTextBlock"]
+
+
+class BetaTextBlock(BaseModel):
+    citations: Optional[List[BetaTextCitation]] = None
+    """Citations supporting the text block.
+
+    The type of citation returned will depend on the type of document being cited.
+    Citing a PDF results in `page_location`, plain text results in `char_location`,
+    and content document results in `content_block_location`.
+    """
+
+    text: str
+
+    type: Literal["text"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block_param.py
new file mode 100644
index 00000000..e40b03a5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_block_param.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable, Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_text_citation_param import BetaTextCitationParam
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaTextBlockParam"]
+
+
+class BetaTextBlockParam(TypedDict, total=False):
+    text: Required[str]
+
+    type: Required[Literal["text"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
+
+    citations: Optional[Iterable[BetaTextCitationParam]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation.py
new file mode 100644
index 00000000..538878b6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from .beta_citation_char_location import BetaCitationCharLocation
+from .beta_citation_page_location import BetaCitationPageLocation
+from .beta_citation_content_block_location import BetaCitationContentBlockLocation
+
+__all__ = ["BetaTextCitation"]
+
+BetaTextCitation: TypeAlias = Annotated[
+    Union[BetaCitationCharLocation, BetaCitationPageLocation, BetaCitationContentBlockLocation],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation_param.py
new file mode 100644
index 00000000..b04c3305
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_citation_param.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .beta_citation_char_location_param import BetaCitationCharLocationParam
+from .beta_citation_page_location_param import BetaCitationPageLocationParam
+from .beta_citation_content_block_location_param import BetaCitationContentBlockLocationParam
+
+__all__ = ["BetaTextCitationParam"]
+
+BetaTextCitationParam: TypeAlias = Union[
+    BetaCitationCharLocationParam, BetaCitationPageLocationParam, BetaCitationContentBlockLocationParam
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_delta.py
new file mode 100644
index 00000000..b94ba5ea
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_text_delta.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaTextDelta"]
+
+
+class BetaTextDelta(BaseModel):
+    text: str
+
+    type: Literal["text_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block.py
new file mode 100644
index 00000000..9a9c1df8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaThinkingBlock"]
+
+
+class BetaThinkingBlock(BaseModel):
+    signature: str
+
+    thinking: str
+
+    type: Literal["thinking"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block_param.py
new file mode 100644
index 00000000..5bd43180
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_block_param.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaThinkingBlockParam"]
+
+
+class BetaThinkingBlockParam(TypedDict, total=False):
+    signature: Required[str]
+
+    thinking: Required[str]
+
+    type: Required[Literal["thinking"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_disabled_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_disabled_param.py
new file mode 100644
index 00000000..e7c4a2a0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_disabled_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaThinkingConfigDisabledParam"]
+
+
+class BetaThinkingConfigDisabledParam(TypedDict, total=False):
+    type: Required[Literal["disabled"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_enabled_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_enabled_param.py
new file mode 100644
index 00000000..f9490c4c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_enabled_param.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaThinkingConfigEnabledParam"]
+
+
+class BetaThinkingConfigEnabledParam(TypedDict, total=False):
+    budget_tokens: Required[int]
+    """Determines how many tokens Claude can use for its internal reasoning process.
+
+    Larger budgets can enable more thorough analysis for complex problems, improving
+    response quality.
+
+    Must be ≥1024 and less than `max_tokens`.
+
+    See
+    [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+    for details.
+    """
+
+    type: Required[Literal["enabled"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_param.py
new file mode 100644
index 00000000..47494239
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_config_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .beta_thinking_config_enabled_param import BetaThinkingConfigEnabledParam
+from .beta_thinking_config_disabled_param import BetaThinkingConfigDisabledParam
+
+__all__ = ["BetaThinkingConfigParam"]
+
+BetaThinkingConfigParam: TypeAlias = Union[BetaThinkingConfigEnabledParam, BetaThinkingConfigDisabledParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_delta.py
new file mode 100644
index 00000000..790a304e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_thinking_delta.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaThinkingDelta"]
+
+
+class BetaThinkingDelta(BaseModel):
+    thinking: str
+
+    type: Literal["thinking_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20241022_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20241022_param.py
new file mode 100644
index 00000000..82ed02b3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20241022_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolBash20241022Param"]
+
+
+class BetaToolBash20241022Param(TypedDict, total=False):
+    name: Required[Literal["bash"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["bash_20241022"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20250124_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20250124_param.py
new file mode 100644
index 00000000..3fcab440
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_bash_20250124_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolBash20250124Param"]
+
+
+class BetaToolBash20250124Param(TypedDict, total=False):
+    name: Required[Literal["bash"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["bash_20250124"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_any_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_any_param.py
new file mode 100644
index 00000000..6cdac00a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_any_param.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaToolChoiceAnyParam"]
+
+
+class BetaToolChoiceAnyParam(TypedDict, total=False):
+    type: Required[Literal["any"]]
+
+    disable_parallel_tool_use: bool
+    """Whether to disable parallel tool use.
+
+    Defaults to `false`. If set to `true`, the model will output exactly one tool
+    use.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_auto_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_auto_param.py
new file mode 100644
index 00000000..e2f20572
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_auto_param.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaToolChoiceAutoParam"]
+
+
+class BetaToolChoiceAutoParam(TypedDict, total=False):
+    type: Required[Literal["auto"]]
+
+    disable_parallel_tool_use: bool
+    """Whether to disable parallel tool use.
+
+    Defaults to `false`. If set to `true`, the model will output at most one tool
+    use.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_none_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_none_param.py
new file mode 100644
index 00000000..3a0951a4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_none_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaToolChoiceNoneParam"]
+
+
+class BetaToolChoiceNoneParam(TypedDict, total=False):
+    type: Required[Literal["none"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_param.py
new file mode 100644
index 00000000..ff6a51aa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_param.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .beta_tool_choice_any_param import BetaToolChoiceAnyParam
+from .beta_tool_choice_auto_param import BetaToolChoiceAutoParam
+from .beta_tool_choice_none_param import BetaToolChoiceNoneParam
+from .beta_tool_choice_tool_param import BetaToolChoiceToolParam
+
+__all__ = ["BetaToolChoiceParam"]
+
+BetaToolChoiceParam: TypeAlias = Union[
+    BetaToolChoiceAutoParam, BetaToolChoiceAnyParam, BetaToolChoiceToolParam, BetaToolChoiceNoneParam
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_tool_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_tool_param.py
new file mode 100644
index 00000000..e826237a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_choice_tool_param.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaToolChoiceToolParam"]
+
+
+class BetaToolChoiceToolParam(TypedDict, total=False):
+    name: Required[str]
+    """The name of the tool to use."""
+
+    type: Required[Literal["tool"]]
+
+    disable_parallel_tool_use: bool
+    """Whether to disable parallel tool use.
+
+    Defaults to `false`. If set to `true`, the model will output exactly one tool
+    use.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20241022_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20241022_param.py
new file mode 100644
index 00000000..b95472be
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20241022_param.py
@@ -0,0 +1,31 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolComputerUse20241022Param"]
+
+
+class BetaToolComputerUse20241022Param(TypedDict, total=False):
+    display_height_px: Required[int]
+    """The height of the display in pixels."""
+
+    display_width_px: Required[int]
+    """The width of the display in pixels."""
+
+    name: Required[Literal["computer"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["computer_20241022"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
+
+    display_number: Optional[int]
+    """The X11 display number (e.g. 0, 1) for the display."""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20250124_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20250124_param.py
new file mode 100644
index 00000000..089d67aa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_computer_use_20250124_param.py
@@ -0,0 +1,31 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolComputerUse20250124Param"]
+
+
+class BetaToolComputerUse20250124Param(TypedDict, total=False):
+    display_height_px: Required[int]
+    """The height of the display in pixels."""
+
+    display_width_px: Required[int]
+    """The width of the display in pixels."""
+
+    name: Required[Literal["computer"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["computer_20250124"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
+
+    display_number: Optional[int]
+    """The X11 display number (e.g. 0, 1) for the display."""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_param.py
new file mode 100644
index 00000000..da9d43bc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_param.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Union, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolParam", "InputSchema"]
+
+
+class InputSchemaTyped(TypedDict, total=False):
+    type: Required[Literal["object"]]
+
+    properties: Optional[object]
+
+
+InputSchema: TypeAlias = Union[InputSchemaTyped, Dict[str, object]]
+
+
+class BetaToolParam(TypedDict, total=False):
+    input_schema: Required[InputSchema]
+    """[JSON schema](https://json-schema.org/draft/2020-12) for this tool's input.
+
+    This defines the shape of the `input` that your tool accepts and that the model
+    will produce.
+    """
+
+    name: Required[str]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
+
+    description: str
+    """Description of what this tool does.
+
+    Tool descriptions should be as detailed as possible. The more information that
+    the model has about what the tool is and how to use it, the better it will
+    perform. You can use natural language descriptions to reinforce important
+    aspects of the tool input JSON schema.
+    """
+
+    type: Optional[Literal["custom"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_result_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_result_block_param.py
new file mode 100644
index 00000000..9418b650
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_result_block_param.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .beta_text_block_param import BetaTextBlockParam
+from .beta_image_block_param import BetaImageBlockParam
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolResultBlockParam", "Content"]
+
+Content: TypeAlias = Union[BetaTextBlockParam, BetaImageBlockParam]
+
+
+class BetaToolResultBlockParam(TypedDict, total=False):
+    tool_use_id: Required[str]
+
+    type: Required[Literal["tool_result"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
+
+    content: Union[str, Iterable[Content]]
+
+    is_error: bool
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20241022_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20241022_param.py
new file mode 100644
index 00000000..86c93278
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20241022_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolTextEditor20241022Param"]
+
+
+class BetaToolTextEditor20241022Param(TypedDict, total=False):
+    name: Required[Literal["str_replace_editor"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["text_editor_20241022"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20250124_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20250124_param.py
new file mode 100644
index 00000000..07b86bd5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_text_editor_20250124_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolTextEditor20250124Param"]
+
+
+class BetaToolTextEditor20250124Param(TypedDict, total=False):
+    name: Required[Literal["str_replace_editor"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["text_editor_20250124"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_union_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_union_param.py
new file mode 100644
index 00000000..d37480da
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_union_param.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .beta_tool_param import BetaToolParam
+from .beta_tool_bash_20241022_param import BetaToolBash20241022Param
+from .beta_tool_bash_20250124_param import BetaToolBash20250124Param
+from .beta_tool_text_editor_20241022_param import BetaToolTextEditor20241022Param
+from .beta_tool_text_editor_20250124_param import BetaToolTextEditor20250124Param
+from .beta_tool_computer_use_20241022_param import BetaToolComputerUse20241022Param
+from .beta_tool_computer_use_20250124_param import BetaToolComputerUse20250124Param
+
+__all__ = ["BetaToolUnionParam"]
+
+BetaToolUnionParam: TypeAlias = Union[
+    BetaToolParam,
+    BetaToolComputerUse20241022Param,
+    BetaToolBash20241022Param,
+    BetaToolTextEditor20241022Param,
+    BetaToolComputerUse20250124Param,
+    BetaToolBash20250124Param,
+    BetaToolTextEditor20250124Param,
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block.py
new file mode 100644
index 00000000..7cfc0c33
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BetaToolUseBlock"]
+
+
+class BetaToolUseBlock(BaseModel):
+    id: str
+
+    input: object
+
+    name: str
+
+    type: Literal["tool_use"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block_param.py
new file mode 100644
index 00000000..603dc85f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_tool_use_block_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .beta_cache_control_ephemeral_param import BetaCacheControlEphemeralParam
+
+__all__ = ["BetaToolUseBlockParam"]
+
+
+class BetaToolUseBlockParam(TypedDict, total=False):
+    id: Required[str]
+
+    input: Required[object]
+
+    name: Required[str]
+
+    type: Required[Literal["tool_use"]]
+
+    cache_control: Optional[BetaCacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_image_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_image_source_param.py
new file mode 100644
index 00000000..a094a433
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_image_source_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaURLImageSourceParam"]
+
+
+class BetaURLImageSourceParam(TypedDict, total=False):
+    type: Required[Literal["url"]]
+
+    url: Required[str]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_pdf_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_pdf_source_param.py
new file mode 100644
index 00000000..acc1eabf
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_url_pdf_source_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["BetaURLPDFSourceParam"]
+
+
+class BetaURLPDFSourceParam(TypedDict, total=False):
+    type: Required[Literal["url"]]
+
+    url: Required[str]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_usage.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_usage.py
new file mode 100644
index 00000000..0d956c70
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/beta_usage.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from ..._models import BaseModel
+
+__all__ = ["BetaUsage"]
+
+
+class BetaUsage(BaseModel):
+    cache_creation_input_tokens: Optional[int] = None
+    """The number of input tokens used to create the cache entry."""
+
+    cache_read_input_tokens: Optional[int] = None
+    """The number of input tokens read from the cache."""
+
+    input_tokens: int
+    """The number of input tokens which were used."""
+
+    output_tokens: int
+    """The number of output tokens which were used."""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/message_count_tokens_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/message_count_tokens_params.py
new file mode 100644
index 00000000..056c4289
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/message_count_tokens_params.py
@@ -0,0 +1,234 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List, Union, Iterable
+from typing_extensions import Required, Annotated, TypeAlias, TypedDict
+
+from ..._utils import PropertyInfo
+from ..model_param import ModelParam
+from .beta_tool_param import BetaToolParam
+from .beta_message_param import BetaMessageParam
+from ..anthropic_beta_param import AnthropicBetaParam
+from .beta_text_block_param import BetaTextBlockParam
+from .beta_tool_choice_param import BetaToolChoiceParam
+from .beta_thinking_config_param import BetaThinkingConfigParam
+from .beta_tool_bash_20241022_param import BetaToolBash20241022Param
+from .beta_tool_bash_20250124_param import BetaToolBash20250124Param
+from .beta_tool_text_editor_20241022_param import BetaToolTextEditor20241022Param
+from .beta_tool_text_editor_20250124_param import BetaToolTextEditor20250124Param
+from .beta_tool_computer_use_20241022_param import BetaToolComputerUse20241022Param
+from .beta_tool_computer_use_20250124_param import BetaToolComputerUse20250124Param
+
+__all__ = ["MessageCountTokensParams", "Tool"]
+
+
+class MessageCountTokensParams(TypedDict, total=False):
+    messages: Required[Iterable[BetaMessageParam]]
+    """Input messages.
+
+    Our models are trained to operate on alternating `user` and `assistant`
+    conversational turns. When creating a new `Message`, you specify the prior
+    conversational turns with the `messages` parameter, and the model then generates
+    the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+    in your request will be combined into a single turn.
+
+    Each input message must be an object with a `role` and `content`. You can
+    specify a single `user`-role message, or you can include multiple `user` and
+    `assistant` messages.
+
+    If the final message uses the `assistant` role, the response content will
+    continue immediately from the content in that message. This can be used to
+    constrain part of the model's response.
+
+    Example with a single `user` message:
+
+    ```json
+    [{ "role": "user", "content": "Hello, Claude" }]
+    ```
+
+    Example with multiple conversational turns:
+
+    ```json
+    [
+      { "role": "user", "content": "Hello there." },
+      { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+      { "role": "user", "content": "Can you explain LLMs in plain English?" }
+    ]
+    ```
+
+    Example with a partially-filled response from Claude:
+
+    ```json
+    [
+      {
+        "role": "user",
+        "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+      },
+      { "role": "assistant", "content": "The best answer is (" }
+    ]
+    ```
+
+    Each input message `content` may be either a single `string` or an array of
+    content blocks, where each block has a specific `type`. Using a `string` for
+    `content` is shorthand for an array of one content block of type `"text"`. The
+    following input messages are equivalent:
+
+    ```json
+    { "role": "user", "content": "Hello, Claude" }
+    ```
+
+    ```json
+    { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+    ```
+
+    Starting with Claude 3 models, you can also send image content blocks:
+
+    ```json
+    {
+      "role": "user",
+      "content": [
+        {
+          "type": "image",
+          "source": {
+            "type": "base64",
+            "media_type": "image/jpeg",
+            "data": "/9j/4AAQSkZJRg..."
+          }
+        },
+        { "type": "text", "text": "What is in this image?" }
+      ]
+    }
+    ```
+
+    We currently support the `base64` source type for images, and the `image/jpeg`,
+    `image/png`, `image/gif`, and `image/webp` media types.
+
+    See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+    more input examples.
+
+    Note that if you want to include a
+    [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+    the top-level `system` parameter — there is no `"system"` role for input
+    messages in the Messages API.
+    """
+
+    model: Required[ModelParam]
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    system: Union[str, Iterable[BetaTextBlockParam]]
+    """System prompt.
+
+    A system prompt is a way of providing context and instructions to Claude, such
+    as specifying a particular goal or role. See our
+    [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+    """
+
+    thinking: BetaThinkingConfigParam
+    """Configuration for enabling Claude's extended thinking.
+
+    When enabled, responses include `thinking` content blocks showing Claude's
+    thinking process before the final answer. Requires a minimum budget of 1,024
+    tokens and counts towards your `max_tokens` limit.
+
+    See
+    [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+    for details.
+    """
+
+    tool_choice: BetaToolChoiceParam
+    """How the model should use the provided tools.
+
+    The model can use a specific tool, any available tool, decide by itself, or not
+    use tools at all.
+    """
+
+    tools: Iterable[Tool]
+    """Definitions of tools that the model may use.
+
+    If you include `tools` in your API request, the model may return `tool_use`
+    content blocks that represent the model's use of those tools. You can then run
+    those tools using the tool input generated by the model and then optionally
+    return results back to the model using `tool_result` content blocks.
+
+    Each tool definition includes:
+
+    - `name`: Name of the tool.
+    - `description`: Optional, but strongly-recommended description of the tool.
+    - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+      tool `input` shape that the model will produce in `tool_use` output content
+      blocks.
+
+    For example, if you defined `tools` as:
+
+    ```json
+    [
+      {
+        "name": "get_stock_price",
+        "description": "Get the current stock price for a given ticker symbol.",
+        "input_schema": {
+          "type": "object",
+          "properties": {
+            "ticker": {
+              "type": "string",
+              "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+            }
+          },
+          "required": ["ticker"]
+        }
+      }
+    ]
+    ```
+
+    And then asked the model "What's the S&P 500 at today?", the model might produce
+    `tool_use` content blocks in the response like this:
+
+    ```json
+    [
+      {
+        "type": "tool_use",
+        "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "name": "get_stock_price",
+        "input": { "ticker": "^GSPC" }
+      }
+    ]
+    ```
+
+    You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+    input, and return the following back to the model in a subsequent `user`
+    message:
+
+    ```json
+    [
+      {
+        "type": "tool_result",
+        "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "content": "259.75 USD"
+      }
+    ]
+    ```
+
+    Tools can be used for workflows that include running client-side tools and
+    functions, or more generally whenever you want the model to produce a particular
+    JSON structure of output.
+
+    See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+    """
+
+    betas: Annotated[List[AnthropicBetaParam], PropertyInfo(alias="anthropic-beta")]
+    """Optional header to specify the beta version(s) you want to use."""
+
+
+Tool: TypeAlias = Union[
+    BetaToolParam,
+    BetaToolComputerUse20241022Param,
+    BetaToolBash20241022Param,
+    BetaToolTextEditor20241022Param,
+    BetaToolComputerUse20250124Param,
+    BetaToolBash20250124Param,
+    BetaToolTextEditor20250124Param,
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/message_create_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/message_create_params.py
new file mode 100644
index 00000000..e05f92da
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/message_create_params.py
@@ -0,0 +1,297 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List, Union, Iterable
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+from ..model_param import ModelParam
+from .beta_message_param import BetaMessageParam
+from .beta_metadata_param import BetaMetadataParam
+from ..anthropic_beta_param import AnthropicBetaParam
+from .beta_text_block_param import BetaTextBlockParam
+from .beta_tool_union_param import BetaToolUnionParam
+from .beta_tool_choice_param import BetaToolChoiceParam
+from .beta_thinking_config_param import BetaThinkingConfigParam
+
+__all__ = ["MessageCreateParamsBase", "MessageCreateParamsNonStreaming", "MessageCreateParamsStreaming"]
+
+
+class MessageCreateParamsBase(TypedDict, total=False):
+    max_tokens: Required[int]
+    """The maximum number of tokens to generate before stopping.
+
+    Note that our models may stop _before_ reaching this maximum. This parameter
+    only specifies the absolute maximum number of tokens to generate.
+
+    Different models have different maximum values for this parameter. See
+    [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+    """
+
+    messages: Required[Iterable[BetaMessageParam]]
+    """Input messages.
+
+    Our models are trained to operate on alternating `user` and `assistant`
+    conversational turns. When creating a new `Message`, you specify the prior
+    conversational turns with the `messages` parameter, and the model then generates
+    the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+    in your request will be combined into a single turn.
+
+    Each input message must be an object with a `role` and `content`. You can
+    specify a single `user`-role message, or you can include multiple `user` and
+    `assistant` messages.
+
+    If the final message uses the `assistant` role, the response content will
+    continue immediately from the content in that message. This can be used to
+    constrain part of the model's response.
+
+    Example with a single `user` message:
+
+    ```json
+    [{ "role": "user", "content": "Hello, Claude" }]
+    ```
+
+    Example with multiple conversational turns:
+
+    ```json
+    [
+      { "role": "user", "content": "Hello there." },
+      { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+      { "role": "user", "content": "Can you explain LLMs in plain English?" }
+    ]
+    ```
+
+    Example with a partially-filled response from Claude:
+
+    ```json
+    [
+      {
+        "role": "user",
+        "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+      },
+      { "role": "assistant", "content": "The best answer is (" }
+    ]
+    ```
+
+    Each input message `content` may be either a single `string` or an array of
+    content blocks, where each block has a specific `type`. Using a `string` for
+    `content` is shorthand for an array of one content block of type `"text"`. The
+    following input messages are equivalent:
+
+    ```json
+    { "role": "user", "content": "Hello, Claude" }
+    ```
+
+    ```json
+    { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+    ```
+
+    Starting with Claude 3 models, you can also send image content blocks:
+
+    ```json
+    {
+      "role": "user",
+      "content": [
+        {
+          "type": "image",
+          "source": {
+            "type": "base64",
+            "media_type": "image/jpeg",
+            "data": "/9j/4AAQSkZJRg..."
+          }
+        },
+        { "type": "text", "text": "What is in this image?" }
+      ]
+    }
+    ```
+
+    We currently support the `base64` source type for images, and the `image/jpeg`,
+    `image/png`, `image/gif`, and `image/webp` media types.
+
+    See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+    more input examples.
+
+    Note that if you want to include a
+    [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+    the top-level `system` parameter — there is no `"system"` role for input
+    messages in the Messages API.
+    """
+
+    model: Required[ModelParam]
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    metadata: BetaMetadataParam
+    """An object describing metadata about the request."""
+
+    stop_sequences: List[str]
+    """Custom text sequences that will cause the model to stop generating.
+
+    Our models will normally stop when they have naturally completed their turn,
+    which will result in a response `stop_reason` of `"end_turn"`.
+
+    If you want the model to stop generating when it encounters custom strings of
+    text, you can use the `stop_sequences` parameter. If the model encounters one of
+    the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+    and the response `stop_sequence` value will contain the matched stop sequence.
+    """
+
+    system: Union[str, Iterable[BetaTextBlockParam]]
+    """System prompt.
+
+    A system prompt is a way of providing context and instructions to Claude, such
+    as specifying a particular goal or role. See our
+    [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+    """
+
+    temperature: float
+    """Amount of randomness injected into the response.
+
+    Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+    for analytical / multiple choice, and closer to `1.0` for creative and
+    generative tasks.
+
+    Note that even with `temperature` of `0.0`, the results will not be fully
+    deterministic.
+    """
+
+    thinking: BetaThinkingConfigParam
+    """Configuration for enabling Claude's extended thinking.
+
+    When enabled, responses include `thinking` content blocks showing Claude's
+    thinking process before the final answer. Requires a minimum budget of 1,024
+    tokens and counts towards your `max_tokens` limit.
+
+    See
+    [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+    for details.
+    """
+
+    tool_choice: BetaToolChoiceParam
+    """How the model should use the provided tools.
+
+    The model can use a specific tool, any available tool, decide by itself, or not
+    use tools at all.
+    """
+
+    tools: Iterable[BetaToolUnionParam]
+    """Definitions of tools that the model may use.
+
+    If you include `tools` in your API request, the model may return `tool_use`
+    content blocks that represent the model's use of those tools. You can then run
+    those tools using the tool input generated by the model and then optionally
+    return results back to the model using `tool_result` content blocks.
+
+    Each tool definition includes:
+
+    - `name`: Name of the tool.
+    - `description`: Optional, but strongly-recommended description of the tool.
+    - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+      tool `input` shape that the model will produce in `tool_use` output content
+      blocks.
+
+    For example, if you defined `tools` as:
+
+    ```json
+    [
+      {
+        "name": "get_stock_price",
+        "description": "Get the current stock price for a given ticker symbol.",
+        "input_schema": {
+          "type": "object",
+          "properties": {
+            "ticker": {
+              "type": "string",
+              "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+            }
+          },
+          "required": ["ticker"]
+        }
+      }
+    ]
+    ```
+
+    And then asked the model "What's the S&P 500 at today?", the model might produce
+    `tool_use` content blocks in the response like this:
+
+    ```json
+    [
+      {
+        "type": "tool_use",
+        "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "name": "get_stock_price",
+        "input": { "ticker": "^GSPC" }
+      }
+    ]
+    ```
+
+    You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+    input, and return the following back to the model in a subsequent `user`
+    message:
+
+    ```json
+    [
+      {
+        "type": "tool_result",
+        "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "content": "259.75 USD"
+      }
+    ]
+    ```
+
+    Tools can be used for workflows that include running client-side tools and
+    functions, or more generally whenever you want the model to produce a particular
+    JSON structure of output.
+
+    See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+    """
+
+    top_k: int
+    """Only sample from the top K options for each subsequent token.
+
+    Used to remove "long tail" low probability responses.
+    [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+    Recommended for advanced use cases only. You usually only need to use
+    `temperature`.
+    """
+
+    top_p: float
+    """Use nucleus sampling.
+
+    In nucleus sampling, we compute the cumulative distribution over all the options
+    for each subsequent token in decreasing probability order and cut it off once it
+    reaches a particular probability specified by `top_p`. You should either alter
+    `temperature` or `top_p`, but not both.
+
+    Recommended for advanced use cases only. You usually only need to use
+    `temperature`.
+    """
+
+    betas: Annotated[List[AnthropicBetaParam], PropertyInfo(alias="anthropic-beta")]
+    """Optional header to specify the beta version(s) you want to use."""
+
+
+class MessageCreateParamsNonStreaming(MessageCreateParamsBase, total=False):
+    stream: Literal[False]
+    """Whether to incrementally stream the response using server-sent events.
+
+    See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+    details.
+    """
+
+
+class MessageCreateParamsStreaming(MessageCreateParamsBase):
+    stream: Required[Literal[True]]
+    """Whether to incrementally stream the response using server-sent events.
+
+    See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+    details.
+    """
+
+
+MessageCreateParams = Union[MessageCreateParamsNonStreaming, MessageCreateParamsStreaming]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/__init__.py
new file mode 100644
index 00000000..fef14dd1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/__init__.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .batch_list_params import BatchListParams as BatchListParams
+from .beta_message_batch import BetaMessageBatch as BetaMessageBatch
+from .batch_create_params import BatchCreateParams as BatchCreateParams
+from .beta_message_batch_result import BetaMessageBatchResult as BetaMessageBatchResult
+from .beta_deleted_message_batch import BetaDeletedMessageBatch as BetaDeletedMessageBatch
+from .beta_message_batch_errored_result import BetaMessageBatchErroredResult as BetaMessageBatchErroredResult
+from .beta_message_batch_expired_result import BetaMessageBatchExpiredResult as BetaMessageBatchExpiredResult
+from .beta_message_batch_request_counts import BetaMessageBatchRequestCounts as BetaMessageBatchRequestCounts
+from .beta_message_batch_canceled_result import BetaMessageBatchCanceledResult as BetaMessageBatchCanceledResult
+from .beta_message_batch_succeeded_result import BetaMessageBatchSucceededResult as BetaMessageBatchSucceededResult
+from .beta_message_batch_individual_response import (
+    BetaMessageBatchIndividualResponse as BetaMessageBatchIndividualResponse,
+)
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_create_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_create_params.py
new file mode 100644
index 00000000..8eb9c4af
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_create_params.py
@@ -0,0 +1,41 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List, Iterable
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+from ...anthropic_beta_param import AnthropicBetaParam
+from ..message_create_params import MessageCreateParamsNonStreaming
+
+__all__ = ["BatchCreateParams", "Request"]
+
+
+class BatchCreateParams(TypedDict, total=False):
+    requests: Required[Iterable[Request]]
+    """List of requests for prompt completion.
+
+    Each is an individual request to create a Message.
+    """
+
+    betas: Annotated[List[AnthropicBetaParam], PropertyInfo(alias="anthropic-beta")]
+    """Optional header to specify the beta version(s) you want to use."""
+
+
+class Request(TypedDict, total=False):
+    custom_id: Required[str]
+    """Developer-provided ID created for each request in a Message Batch.
+
+    Useful for matching results to requests, as results may be given out of request
+    order.
+
+    Must be unique for each request within the Message Batch.
+    """
+
+    params: Required[MessageCreateParamsNonStreaming]
+    """Messages API creation parameters for the individual request.
+
+    See the [Messages API reference](/en/api/messages) for full documentation on
+    available parameters.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_list_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_list_params.py
new file mode 100644
index 00000000..3f406251
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/batch_list_params.py
@@ -0,0 +1,34 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+from ...anthropic_beta_param import AnthropicBetaParam
+
+__all__ = ["BatchListParams"]
+
+
+class BatchListParams(TypedDict, total=False):
+    after_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately after this object.
+    """
+
+    before_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately before this object.
+    """
+
+    limit: int
+    """Number of items to return per page.
+
+    Defaults to `20`. Ranges from `1` to `1000`.
+    """
+
+    betas: Annotated[List[AnthropicBetaParam], PropertyInfo(alias="anthropic-beta")]
+    """Optional header to specify the beta version(s) you want to use."""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_deleted_message_batch.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_deleted_message_batch.py
new file mode 100644
index 00000000..f7dd1d52
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_deleted_message_batch.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+
+__all__ = ["BetaDeletedMessageBatch"]
+
+
+class BetaDeletedMessageBatch(BaseModel):
+    id: str
+    """ID of the Message Batch."""
+
+    type: Literal["message_batch_deleted"]
+    """Deleted object type.
+
+    For Message Batches, this is always `"message_batch_deleted"`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch.py
new file mode 100644
index 00000000..1ea92c3a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch.py
@@ -0,0 +1,77 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+from .beta_message_batch_request_counts import BetaMessageBatchRequestCounts
+
+__all__ = ["BetaMessageBatch"]
+
+
+class BetaMessageBatch(BaseModel):
+    id: str
+    """Unique object identifier.
+
+    The format and length of IDs may change over time.
+    """
+
+    archived_at: Optional[datetime] = None
+    """
+    RFC 3339 datetime string representing the time at which the Message Batch was
+    archived and its results became unavailable.
+    """
+
+    cancel_initiated_at: Optional[datetime] = None
+    """
+    RFC 3339 datetime string representing the time at which cancellation was
+    initiated for the Message Batch. Specified only if cancellation was initiated.
+    """
+
+    created_at: datetime
+    """
+    RFC 3339 datetime string representing the time at which the Message Batch was
+    created.
+    """
+
+    ended_at: Optional[datetime] = None
+    """
+    RFC 3339 datetime string representing the time at which processing for the
+    Message Batch ended. Specified only once processing ends.
+
+    Processing ends when every request in a Message Batch has either succeeded,
+    errored, canceled, or expired.
+    """
+
+    expires_at: datetime
+    """
+    RFC 3339 datetime string representing the time at which the Message Batch will
+    expire and end processing, which is 24 hours after creation.
+    """
+
+    processing_status: Literal["in_progress", "canceling", "ended"]
+    """Processing status of the Message Batch."""
+
+    request_counts: BetaMessageBatchRequestCounts
+    """Tallies requests within the Message Batch, categorized by their status.
+
+    Requests start as `processing` and move to one of the other statuses only once
+    processing of the entire batch ends. The sum of all values always matches the
+    total number of requests in the batch.
+    """
+
+    results_url: Optional[str] = None
+    """URL to a `.jsonl` file containing the results of the Message Batch requests.
+
+    Specified only once processing ends.
+
+    Results in the file are not guaranteed to be in the same order as requests. Use
+    the `custom_id` field to match results to requests.
+    """
+
+    type: Literal["message_batch"]
+    """Object type.
+
+    For Message Batches, this is always `"message_batch"`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_canceled_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_canceled_result.py
new file mode 100644
index 00000000..e5dae348
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_canceled_result.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+
+__all__ = ["BetaMessageBatchCanceledResult"]
+
+
+class BetaMessageBatchCanceledResult(BaseModel):
+    type: Literal["canceled"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_errored_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_errored_result.py
new file mode 100644
index 00000000..44ea9027
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_errored_result.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+from ...beta_error_response import BetaErrorResponse
+
+__all__ = ["BetaMessageBatchErroredResult"]
+
+
+class BetaMessageBatchErroredResult(BaseModel):
+    error: BetaErrorResponse
+
+    type: Literal["errored"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_expired_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_expired_result.py
new file mode 100644
index 00000000..0dbfde41
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_expired_result.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+
+__all__ = ["BetaMessageBatchExpiredResult"]
+
+
+class BetaMessageBatchExpiredResult(BaseModel):
+    type: Literal["expired"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_individual_response.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_individual_response.py
new file mode 100644
index 00000000..8c493934
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_individual_response.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from ...._models import BaseModel
+from .beta_message_batch_result import BetaMessageBatchResult
+
+__all__ = ["BetaMessageBatchIndividualResponse"]
+
+
+class BetaMessageBatchIndividualResponse(BaseModel):
+    custom_id: str
+    """Developer-provided ID created for each request in a Message Batch.
+
+    Useful for matching results to requests, as results may be given out of request
+    order.
+
+    Must be unique for each request within the Message Batch.
+    """
+
+    result: BetaMessageBatchResult
+    """Processing result for this request.
+
+    Contains a Message output if processing was successful, an error response if
+    processing failed, or the reason why processing was not attempted, such as
+    cancellation or expiration.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_request_counts.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_request_counts.py
new file mode 100644
index 00000000..48e6952f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_request_counts.py
@@ -0,0 +1,35 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from ...._models import BaseModel
+
+__all__ = ["BetaMessageBatchRequestCounts"]
+
+
+class BetaMessageBatchRequestCounts(BaseModel):
+    canceled: int
+    """Number of requests in the Message Batch that have been canceled.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
+
+    errored: int
+    """Number of requests in the Message Batch that encountered an error.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
+
+    expired: int
+    """Number of requests in the Message Batch that have expired.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
+
+    processing: int
+    """Number of requests in the Message Batch that are processing."""
+
+    succeeded: int
+    """Number of requests in the Message Batch that have completed successfully.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_result.py
new file mode 100644
index 00000000..78ca7317
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_result.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from ...._utils import PropertyInfo
+from .beta_message_batch_errored_result import BetaMessageBatchErroredResult
+from .beta_message_batch_expired_result import BetaMessageBatchExpiredResult
+from .beta_message_batch_canceled_result import BetaMessageBatchCanceledResult
+from .beta_message_batch_succeeded_result import BetaMessageBatchSucceededResult
+
+__all__ = ["BetaMessageBatchResult"]
+
+BetaMessageBatchResult: TypeAlias = Annotated[
+    Union[
+        BetaMessageBatchSucceededResult,
+        BetaMessageBatchErroredResult,
+        BetaMessageBatchCanceledResult,
+        BetaMessageBatchExpiredResult,
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_succeeded_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_succeeded_result.py
new file mode 100644
index 00000000..94389d60
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/messages/beta_message_batch_succeeded_result.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+from ..beta_message import BetaMessage
+
+__all__ = ["BetaMessageBatchSucceededResult"]
+
+
+class BetaMessageBatchSucceededResult(BaseModel):
+    message: BetaMessage
+
+    type: Literal["succeeded"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta/model_list_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta/model_list_params.py
new file mode 100644
index 00000000..b16d22a3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta/model_list_params.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["ModelListParams"]
+
+
+class ModelListParams(TypedDict, total=False):
+    after_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately after this object.
+    """
+
+    before_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately before this object.
+    """
+
+    limit: int
+    """Number of items to return per page.
+
+    Defaults to `20`. Ranges from `1` to `1000`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_api_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_api_error.py
new file mode 100644
index 00000000..16aa604e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_api_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaAPIError"]
+
+
+class BetaAPIError(BaseModel):
+    message: str
+
+    type: Literal["api_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_authentication_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_authentication_error.py
new file mode 100644
index 00000000..8a555570
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_authentication_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaAuthenticationError"]
+
+
+class BetaAuthenticationError(BaseModel):
+    message: str
+
+    type: Literal["authentication_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_billing_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_billing_error.py
new file mode 100644
index 00000000..1ab37614
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_billing_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaBillingError"]
+
+
+class BetaBillingError(BaseModel):
+    message: str
+
+    type: Literal["billing_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_error.py
new file mode 100644
index 00000000..029d80dc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_error.py
@@ -0,0 +1,32 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .beta_api_error import BetaAPIError
+from .beta_billing_error import BetaBillingError
+from .beta_not_found_error import BetaNotFoundError
+from .beta_overloaded_error import BetaOverloadedError
+from .beta_permission_error import BetaPermissionError
+from .beta_rate_limit_error import BetaRateLimitError
+from .beta_authentication_error import BetaAuthenticationError
+from .beta_gateway_timeout_error import BetaGatewayTimeoutError
+from .beta_invalid_request_error import BetaInvalidRequestError
+
+__all__ = ["BetaError"]
+
+BetaError: TypeAlias = Annotated[
+    Union[
+        BetaInvalidRequestError,
+        BetaAuthenticationError,
+        BetaBillingError,
+        BetaPermissionError,
+        BetaNotFoundError,
+        BetaRateLimitError,
+        BetaGatewayTimeoutError,
+        BetaAPIError,
+        BetaOverloadedError,
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_error_response.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_error_response.py
new file mode 100644
index 00000000..1751183e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_error_response.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .beta_error import BetaError
+
+__all__ = ["BetaErrorResponse"]
+
+
+class BetaErrorResponse(BaseModel):
+    error: BetaError
+
+    type: Literal["error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_gateway_timeout_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_gateway_timeout_error.py
new file mode 100644
index 00000000..9a29705b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_gateway_timeout_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaGatewayTimeoutError"]
+
+
+class BetaGatewayTimeoutError(BaseModel):
+    message: str
+
+    type: Literal["timeout_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_invalid_request_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_invalid_request_error.py
new file mode 100644
index 00000000..a84d53cc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_invalid_request_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaInvalidRequestError"]
+
+
+class BetaInvalidRequestError(BaseModel):
+    message: str
+
+    type: Literal["invalid_request_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_not_found_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_not_found_error.py
new file mode 100644
index 00000000..3d57cb5a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_not_found_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaNotFoundError"]
+
+
+class BetaNotFoundError(BaseModel):
+    message: str
+
+    type: Literal["not_found_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_overloaded_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_overloaded_error.py
new file mode 100644
index 00000000..ff5dbe81
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_overloaded_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaOverloadedError"]
+
+
+class BetaOverloadedError(BaseModel):
+    message: str
+
+    type: Literal["overloaded_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_permission_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_permission_error.py
new file mode 100644
index 00000000..986cf894
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_permission_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaPermissionError"]
+
+
+class BetaPermissionError(BaseModel):
+    message: str
+
+    type: Literal["permission_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/beta_rate_limit_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/beta_rate_limit_error.py
new file mode 100644
index 00000000..ae3cb1ae
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/beta_rate_limit_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["BetaRateLimitError"]
+
+
+class BetaRateLimitError(BaseModel):
+    message: str
+
+    type: Literal["rate_limit_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/cache_control_ephemeral_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/cache_control_ephemeral_param.py
new file mode 100644
index 00000000..8900071e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/cache_control_ephemeral_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["CacheControlEphemeralParam"]
+
+
+class CacheControlEphemeralParam(TypedDict, total=False):
+    type: Required[Literal["ephemeral"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location.py b/.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location.py
new file mode 100644
index 00000000..011b1066
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CitationCharLocation"]
+
+
+class CitationCharLocation(BaseModel):
+    cited_text: str
+
+    document_index: int
+
+    document_title: Optional[str] = None
+
+    end_char_index: int
+
+    start_char_index: int
+
+    type: Literal["char_location"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location_param.py
new file mode 100644
index 00000000..1cc1dfb1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citation_char_location_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["CitationCharLocationParam"]
+
+
+class CitationCharLocationParam(TypedDict, total=False):
+    cited_text: Required[str]
+
+    document_index: Required[int]
+
+    document_title: Required[Optional[str]]
+
+    end_char_index: Required[int]
+
+    start_char_index: Required[int]
+
+    type: Required[Literal["char_location"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location.py b/.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location.py
new file mode 100644
index 00000000..0df0ce57
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CitationContentBlockLocation"]
+
+
+class CitationContentBlockLocation(BaseModel):
+    cited_text: str
+
+    document_index: int
+
+    document_title: Optional[str] = None
+
+    end_block_index: int
+
+    start_block_index: int
+
+    type: Literal["content_block_location"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location_param.py
new file mode 100644
index 00000000..ee0a6a23
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citation_content_block_location_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["CitationContentBlockLocationParam"]
+
+
+class CitationContentBlockLocationParam(TypedDict, total=False):
+    cited_text: Required[str]
+
+    document_index: Required[int]
+
+    document_title: Required[Optional[str]]
+
+    end_block_index: Required[int]
+
+    start_block_index: Required[int]
+
+    type: Required[Literal["content_block_location"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location.py b/.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location.py
new file mode 100644
index 00000000..94c4d509
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CitationPageLocation"]
+
+
+class CitationPageLocation(BaseModel):
+    cited_text: str
+
+    document_index: int
+
+    document_title: Optional[str] = None
+
+    end_page_number: int
+
+    start_page_number: int
+
+    type: Literal["page_location"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location_param.py
new file mode 100644
index 00000000..483837b5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citation_page_location_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["CitationPageLocationParam"]
+
+
+class CitationPageLocationParam(TypedDict, total=False):
+    cited_text: Required[str]
+
+    document_index: Required[int]
+
+    document_title: Required[Optional[str]]
+
+    end_page_number: Required[int]
+
+    start_page_number: Required[int]
+
+    type: Required[Literal["page_location"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citations_config_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/citations_config_param.py
new file mode 100644
index 00000000..817397f8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citations_config_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["CitationsConfigParam"]
+
+
+class CitationsConfigParam(TypedDict, total=False):
+    enabled: bool
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/citations_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/citations_delta.py
new file mode 100644
index 00000000..3eab03d1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/citations_delta.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+from .citation_char_location import CitationCharLocation
+from .citation_page_location import CitationPageLocation
+from .citation_content_block_location import CitationContentBlockLocation
+
+__all__ = ["CitationsDelta", "Citation"]
+
+Citation: TypeAlias = Annotated[
+    Union[CitationCharLocation, CitationPageLocation, CitationContentBlockLocation], PropertyInfo(discriminator="type")
+]
+
+
+class CitationsDelta(BaseModel):
+    citation: Citation
+
+    type: Literal["citations_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/completion.py b/.venv/lib/python3.12/site-packages/anthropic/types/completion.py
new file mode 100644
index 00000000..e6293210
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/completion.py
@@ -0,0 +1,43 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .model import Model
+from .._models import BaseModel
+
+__all__ = ["Completion"]
+
+
+class Completion(BaseModel):
+    id: str
+    """Unique object identifier.
+
+    The format and length of IDs may change over time.
+    """
+
+    completion: str
+    """The resulting completion up to and excluding the stop sequences."""
+
+    model: Model
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    stop_reason: Optional[str] = None
+    """The reason that we stopped.
+
+    This may be one the following values:
+
+    - `"stop_sequence"`: we reached a stop sequence — either provided by you via the
+      `stop_sequences` parameter, or a stop sequence built into the model
+    - `"max_tokens"`: we exceeded `max_tokens_to_sample` or the model's maximum
+    """
+
+    type: Literal["completion"]
+    """Object type.
+
+    For Text Completions, this is always `"completion"`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/completion_create_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/completion_create_params.py
new file mode 100644
index 00000000..0eb25725
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/completion_create_params.py
@@ -0,0 +1,131 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List, Union
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .model_param import ModelParam
+from .metadata_param import MetadataParam
+
+__all__ = [
+    "CompletionRequestStreamingMetadata",
+    "CompletionRequestNonStreamingMetadata",
+    "CompletionRequestNonStreaming",
+    "CompletionRequestStreaming",
+    "CompletionCreateParamsBase",
+    "Metadata",
+    "CompletionCreateParamsNonStreaming",
+    "CompletionCreateParamsStreaming",
+]
+
+
+class CompletionCreateParamsBase(TypedDict, total=False):
+    max_tokens_to_sample: Required[int]
+    """The maximum number of tokens to generate before stopping.
+
+    Note that our models may stop _before_ reaching this maximum. This parameter
+    only specifies the absolute maximum number of tokens to generate.
+    """
+
+    model: Required[ModelParam]
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    prompt: Required[str]
+    """The prompt that you want Claude to complete.
+
+    For proper response generation you will need to format your prompt using
+    alternating `\n\nHuman:` and `\n\nAssistant:` conversational turns. For example:
+
+    ```
+    "\n\nHuman: {userQuestion}\n\nAssistant:"
+    ```
+
+    See [prompt validation](https://docs.anthropic.com/en/api/prompt-validation) and
+    our guide to
+    [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more
+    details.
+    """
+
+    metadata: MetadataParam
+    """An object describing metadata about the request."""
+
+    stop_sequences: List[str]
+    """Sequences that will cause the model to stop generating.
+
+    Our models stop on `"\n\nHuman:"`, and may include additional built-in stop
+    sequences in the future. By providing the stop_sequences parameter, you may
+    include additional strings that will cause the model to stop generating.
+    """
+
+    temperature: float
+    """Amount of randomness injected into the response.
+
+    Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+    for analytical / multiple choice, and closer to `1.0` for creative and
+    generative tasks.
+
+    Note that even with `temperature` of `0.0`, the results will not be fully
+    deterministic.
+    """
+
+    top_k: int
+    """Only sample from the top K options for each subsequent token.
+
+    Used to remove "long tail" low probability responses.
+    [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+    Recommended for advanced use cases only. You usually only need to use
+    `temperature`.
+    """
+
+    top_p: float
+    """Use nucleus sampling.
+
+    In nucleus sampling, we compute the cumulative distribution over all the options
+    for each subsequent token in decreasing probability order and cut it off once it
+    reaches a particular probability specified by `top_p`. You should either alter
+    `temperature` or `top_p`, but not both.
+
+    Recommended for advanced use cases only. You usually only need to use
+    `temperature`.
+    """
+
+
+Metadata: TypeAlias = MetadataParam
+"""This is deprecated, `MetadataParam` should be used instead"""
+
+
+class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase, total=False):
+    stream: Literal[False]
+    """Whether to incrementally stream the response using server-sent events.
+
+    See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+    """
+
+
+class CompletionCreateParamsStreaming(CompletionCreateParamsBase):
+    stream: Required[Literal[True]]
+    """Whether to incrementally stream the response using server-sent events.
+
+    See [streaming](https://docs.anthropic.com/en/api/streaming) for details.
+    """
+
+
+CompletionRequestStreamingMetadata = MetadataParam
+"""This is deprecated, `MetadataParam` should be used instead"""
+
+CompletionRequestNonStreamingMetadata = MetadataParam
+"""This is deprecated, `MetadataParam` should be used instead"""
+
+CompletionRequestNonStreaming = CompletionCreateParamsNonStreaming
+"""This is deprecated, `CompletionCreateParamsNonStreaming` should be used instead"""
+
+CompletionRequestStreaming = CompletionCreateParamsStreaming
+"""This is deprecated, `CompletionCreateParamsStreaming` should be used instead"""
+
+CompletionCreateParams = Union[CompletionCreateParamsNonStreaming, CompletionCreateParamsStreaming]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/content_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/content_block.py
new file mode 100644
index 00000000..1bc77596
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/content_block.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .text_block import TextBlock
+from .thinking_block import ThinkingBlock
+from .tool_use_block import ToolUseBlock
+from .redacted_thinking_block import RedactedThinkingBlock
+
+__all__ = ["ContentBlock"]
+
+ContentBlock: TypeAlias = Annotated[
+    Union[TextBlock, ToolUseBlock, ThinkingBlock, RedactedThinkingBlock], PropertyInfo(discriminator="type")
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/content_block_delta_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_delta_event.py
new file mode 100644
index 00000000..a32602b4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_delta_event.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .raw_content_block_delta_event import RawContentBlockDeltaEvent
+
+__all__ = ["ContentBlockDeltaEvent"]
+
+ContentBlockDeltaEvent = RawContentBlockDeltaEvent
+"""The RawContentBlockDeltaEvent type should be used instead"""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/content_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_param.py
new file mode 100644
index 00000000..97f132e7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_param.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .text_block_param import TextBlockParam
+from .image_block_param import ImageBlockParam
+from .document_block_param import DocumentBlockParam
+from .thinking_block_param import ThinkingBlockParam
+from .tool_use_block_param import ToolUseBlockParam
+from .tool_result_block_param import ToolResultBlockParam
+from .redacted_thinking_block_param import RedactedThinkingBlockParam
+
+__all__ = ["ContentBlockParam"]
+
+ContentBlockParam: TypeAlias = Union[
+    TextBlockParam,
+    ImageBlockParam,
+    ToolUseBlockParam,
+    ToolResultBlockParam,
+    DocumentBlockParam,
+    ThinkingBlockParam,
+    RedactedThinkingBlockParam,
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_content_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_content_param.py
new file mode 100644
index 00000000..0e70cd25
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_content_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .text_block_param import TextBlockParam
+from .image_block_param import ImageBlockParam
+
+__all__ = ["ContentBlockSourceContentParam"]
+
+ContentBlockSourceContentParam: TypeAlias = Union[TextBlockParam, ImageBlockParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_param.py
new file mode 100644
index 00000000..8050f3e6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_source_param.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable
+from typing_extensions import Literal, Required, TypedDict
+
+from .content_block_source_content_param import ContentBlockSourceContentParam
+
+__all__ = ["ContentBlockSourceParam"]
+
+
+class ContentBlockSourceParam(TypedDict, total=False):
+    content: Required[Union[str, Iterable[ContentBlockSourceContentParam]]]
+
+    type: Required[Literal["content"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/content_block_start_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_start_event.py
new file mode 100644
index 00000000..873cba3b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_start_event.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .raw_content_block_start_event import RawContentBlockStartEvent
+
+__all__ = ["ContentBlockStartEvent"]
+
+ContentBlockStartEvent = RawContentBlockStartEvent
+"""The RawContentBlockStartEvent type should be used instead"""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/content_block_stop_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_stop_event.py
new file mode 100644
index 00000000..36c62c89
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/content_block_stop_event.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .raw_content_block_stop_event import RawContentBlockStopEvent
+
+__all__ = ["ContentBlockStopEvent"]
+
+ContentBlockStopEvent = RawContentBlockStopEvent
+"""The RawContentBlockStopEvent type should be used instead"""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/document_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/document_block_param.py
new file mode 100644
index 00000000..e3285266
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/document_block_param.py
@@ -0,0 +1,31 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .url_pdf_source_param import URLPDFSourceParam
+from .citations_config_param import CitationsConfigParam
+from .base64_pdf_source_param import Base64PDFSourceParam
+from .plain_text_source_param import PlainTextSourceParam
+from .content_block_source_param import ContentBlockSourceParam
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["DocumentBlockParam", "Source"]
+
+Source: TypeAlias = Union[Base64PDFSourceParam, PlainTextSourceParam, ContentBlockSourceParam, URLPDFSourceParam]
+
+
+class DocumentBlockParam(TypedDict, total=False):
+    source: Required[Source]
+
+    type: Required[Literal["document"]]
+
+    cache_control: Optional[CacheControlEphemeralParam]
+
+    citations: CitationsConfigParam
+
+    context: Optional[str]
+
+    title: Optional[str]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/image_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/image_block_param.py
new file mode 100644
index 00000000..914ed6bb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/image_block_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .url_image_source_param import URLImageSourceParam
+from .base64_image_source_param import Base64ImageSourceParam
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["ImageBlockParam", "Source"]
+
+Source: TypeAlias = Union[Base64ImageSourceParam, URLImageSourceParam]
+
+
+class ImageBlockParam(TypedDict, total=False):
+    source: Required[Source]
+
+    type: Required[Literal["image"]]
+
+    cache_control: Optional[CacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/input_json_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/input_json_delta.py
new file mode 100644
index 00000000..5d735d72
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/input_json_delta.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["InputJSONDelta", "InputJsonDelta"]
+
+
+class InputJSONDelta(BaseModel):
+    partial_json: str
+
+    type: Literal["input_json_delta"]
+
+
+InputJsonDelta = InputJSONDelta
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message.py b/.venv/lib/python3.12/site-packages/anthropic/types/message.py
new file mode 100644
index 00000000..6179ee12
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message.py
@@ -0,0 +1,112 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .model import Model
+from .usage import Usage
+from .._models import BaseModel
+from .content_block import ContentBlock, ContentBlock as ContentBlock
+
+__all__ = ["Message"]
+
+
+class Message(BaseModel):
+    id: str
+    """Unique object identifier.
+
+    The format and length of IDs may change over time.
+    """
+
+    content: List[ContentBlock]
+    """Content generated by the model.
+
+    This is an array of content blocks, each of which has a `type` that determines
+    its shape.
+
+    Example:
+
+    ```json
+    [{ "type": "text", "text": "Hi, I'm Claude." }]
+    ```
+
+    If the request input `messages` ended with an `assistant` turn, then the
+    response `content` will continue directly from that last turn. You can use this
+    to constrain the model's output.
+
+    For example, if the input `messages` were:
+
+    ```json
+    [
+      {
+        "role": "user",
+        "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+      },
+      { "role": "assistant", "content": "The best answer is (" }
+    ]
+    ```
+
+    Then the response `content` might be:
+
+    ```json
+    [{ "type": "text", "text": "B)" }]
+    ```
+    """
+
+    model: Model
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    role: Literal["assistant"]
+    """Conversational role of the generated message.
+
+    This will always be `"assistant"`.
+    """
+
+    stop_reason: Optional[Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]] = None
+    """The reason that we stopped.
+
+    This may be one the following values:
+
+    - `"end_turn"`: the model reached a natural stopping point
+    - `"max_tokens"`: we exceeded the requested `max_tokens` or the model's maximum
+    - `"stop_sequence"`: one of your provided custom `stop_sequences` was generated
+    - `"tool_use"`: the model invoked one or more tools
+
+    In non-streaming mode this value is always non-null. In streaming mode, it is
+    null in the `message_start` event and non-null otherwise.
+    """
+
+    stop_sequence: Optional[str] = None
+    """Which custom stop sequence was generated, if any.
+
+    This value will be a non-null string if one of your custom stop sequences was
+    generated.
+    """
+
+    type: Literal["message"]
+    """Object type.
+
+    For Messages, this is always `"message"`.
+    """
+
+    usage: Usage
+    """Billing and rate-limit usage.
+
+    Anthropic's API bills and rate-limits by token counts, as tokens represent the
+    underlying cost to our systems.
+
+    Under the hood, the API transforms requests into a format suitable for the
+    model. The model's output then goes through a parsing stage before becoming an
+    API response. As a result, the token counts in `usage` will not match one-to-one
+    with the exact visible content of an API request or response.
+
+    For example, `output_tokens` will be non-zero, even for an empty string response
+    from Claude.
+
+    Total input tokens in a request is the summation of `input_tokens`,
+    `cache_creation_input_tokens`, and `cache_read_input_tokens`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_params.py
new file mode 100644
index 00000000..ea88dd5d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_params.py
@@ -0,0 +1,212 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable
+from typing_extensions import Required, TypedDict
+
+from .model_param import ModelParam
+from .message_param import MessageParam
+from .text_block_param import TextBlockParam
+from .tool_choice_param import ToolChoiceParam
+from .thinking_config_param import ThinkingConfigParam
+from .message_count_tokens_tool_param import MessageCountTokensToolParam
+
+__all__ = ["MessageCountTokensParams"]
+
+
+class MessageCountTokensParams(TypedDict, total=False):
+    messages: Required[Iterable[MessageParam]]
+    """Input messages.
+
+    Our models are trained to operate on alternating `user` and `assistant`
+    conversational turns. When creating a new `Message`, you specify the prior
+    conversational turns with the `messages` parameter, and the model then generates
+    the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+    in your request will be combined into a single turn.
+
+    Each input message must be an object with a `role` and `content`. You can
+    specify a single `user`-role message, or you can include multiple `user` and
+    `assistant` messages.
+
+    If the final message uses the `assistant` role, the response content will
+    continue immediately from the content in that message. This can be used to
+    constrain part of the model's response.
+
+    Example with a single `user` message:
+
+    ```json
+    [{ "role": "user", "content": "Hello, Claude" }]
+    ```
+
+    Example with multiple conversational turns:
+
+    ```json
+    [
+      { "role": "user", "content": "Hello there." },
+      { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+      { "role": "user", "content": "Can you explain LLMs in plain English?" }
+    ]
+    ```
+
+    Example with a partially-filled response from Claude:
+
+    ```json
+    [
+      {
+        "role": "user",
+        "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+      },
+      { "role": "assistant", "content": "The best answer is (" }
+    ]
+    ```
+
+    Each input message `content` may be either a single `string` or an array of
+    content blocks, where each block has a specific `type`. Using a `string` for
+    `content` is shorthand for an array of one content block of type `"text"`. The
+    following input messages are equivalent:
+
+    ```json
+    { "role": "user", "content": "Hello, Claude" }
+    ```
+
+    ```json
+    { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+    ```
+
+    Starting with Claude 3 models, you can also send image content blocks:
+
+    ```json
+    {
+      "role": "user",
+      "content": [
+        {
+          "type": "image",
+          "source": {
+            "type": "base64",
+            "media_type": "image/jpeg",
+            "data": "/9j/4AAQSkZJRg..."
+          }
+        },
+        { "type": "text", "text": "What is in this image?" }
+      ]
+    }
+    ```
+
+    We currently support the `base64` source type for images, and the `image/jpeg`,
+    `image/png`, `image/gif`, and `image/webp` media types.
+
+    See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+    more input examples.
+
+    Note that if you want to include a
+    [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+    the top-level `system` parameter — there is no `"system"` role for input
+    messages in the Messages API.
+    """
+
+    model: Required[ModelParam]
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    system: Union[str, Iterable[TextBlockParam]]
+    """System prompt.
+
+    A system prompt is a way of providing context and instructions to Claude, such
+    as specifying a particular goal or role. See our
+    [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+    """
+
+    thinking: ThinkingConfigParam
+    """Configuration for enabling Claude's extended thinking.
+
+    When enabled, responses include `thinking` content blocks showing Claude's
+    thinking process before the final answer. Requires a minimum budget of 1,024
+    tokens and counts towards your `max_tokens` limit.
+
+    See
+    [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+    for details.
+    """
+
+    tool_choice: ToolChoiceParam
+    """How the model should use the provided tools.
+
+    The model can use a specific tool, any available tool, decide by itself, or not
+    use tools at all.
+    """
+
+    tools: Iterable[MessageCountTokensToolParam]
+    """Definitions of tools that the model may use.
+
+    If you include `tools` in your API request, the model may return `tool_use`
+    content blocks that represent the model's use of those tools. You can then run
+    those tools using the tool input generated by the model and then optionally
+    return results back to the model using `tool_result` content blocks.
+
+    Each tool definition includes:
+
+    - `name`: Name of the tool.
+    - `description`: Optional, but strongly-recommended description of the tool.
+    - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+      tool `input` shape that the model will produce in `tool_use` output content
+      blocks.
+
+    For example, if you defined `tools` as:
+
+    ```json
+    [
+      {
+        "name": "get_stock_price",
+        "description": "Get the current stock price for a given ticker symbol.",
+        "input_schema": {
+          "type": "object",
+          "properties": {
+            "ticker": {
+              "type": "string",
+              "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+            }
+          },
+          "required": ["ticker"]
+        }
+      }
+    ]
+    ```
+
+    And then asked the model "What's the S&P 500 at today?", the model might produce
+    `tool_use` content blocks in the response like this:
+
+    ```json
+    [
+      {
+        "type": "tool_use",
+        "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "name": "get_stock_price",
+        "input": { "ticker": "^GSPC" }
+      }
+    ]
+    ```
+
+    You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+    input, and return the following back to the model in a subsequent `user`
+    message:
+
+    ```json
+    [
+      {
+        "type": "tool_result",
+        "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "content": "259.75 USD"
+      }
+    ]
+    ```
+
+    Tools can be used for workflows that include running client-side tools and
+    functions, or more generally whenever you want the model to produce a particular
+    JSON structure of output.
+
+    See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_tool_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_tool_param.py
new file mode 100644
index 00000000..e28c0ccf
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_count_tokens_tool_param.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .tool_param import ToolParam
+from .tool_bash_20250124_param import ToolBash20250124Param
+from .tool_text_editor_20250124_param import ToolTextEditor20250124Param
+
+__all__ = ["MessageCountTokensToolParam"]
+
+MessageCountTokensToolParam: TypeAlias = Union[ToolParam, ToolBash20250124Param, ToolTextEditor20250124Param]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_create_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_create_params.py
new file mode 100644
index 00000000..c079bafd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_create_params.py
@@ -0,0 +1,320 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List, Union, Iterable
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .model_param import ModelParam
+from .message_param import MessageParam
+from .metadata_param import MetadataParam
+from .text_block_param import TextBlockParam
+from .tool_union_param import ToolUnionParam
+from .tool_choice_param import ToolChoiceParam
+from .thinking_config_param import ThinkingConfigParam
+from .tool_choice_any_param import ToolChoiceAnyParam
+from .tool_choice_auto_param import ToolChoiceAutoParam
+from .tool_choice_tool_param import ToolChoiceToolParam
+
+__all__ = [
+    "MessageCreateParamsBase",
+    "Metadata",
+    "ToolChoice",
+    "ToolChoiceToolChoiceAuto",
+    "ToolChoiceToolChoiceAny",
+    "ToolChoiceToolChoiceTool",
+    "MessageCreateParamsNonStreaming",
+    "MessageCreateParamsStreaming",
+]
+
+
+class MessageCreateParamsBase(TypedDict, total=False):
+    max_tokens: Required[int]
+    """The maximum number of tokens to generate before stopping.
+
+    Note that our models may stop _before_ reaching this maximum. This parameter
+    only specifies the absolute maximum number of tokens to generate.
+
+    Different models have different maximum values for this parameter. See
+    [models](https://docs.anthropic.com/en/docs/models-overview) for details.
+    """
+
+    messages: Required[Iterable[MessageParam]]
+    """Input messages.
+
+    Our models are trained to operate on alternating `user` and `assistant`
+    conversational turns. When creating a new `Message`, you specify the prior
+    conversational turns with the `messages` parameter, and the model then generates
+    the next `Message` in the conversation. Consecutive `user` or `assistant` turns
+    in your request will be combined into a single turn.
+
+    Each input message must be an object with a `role` and `content`. You can
+    specify a single `user`-role message, or you can include multiple `user` and
+    `assistant` messages.
+
+    If the final message uses the `assistant` role, the response content will
+    continue immediately from the content in that message. This can be used to
+    constrain part of the model's response.
+
+    Example with a single `user` message:
+
+    ```json
+    [{ "role": "user", "content": "Hello, Claude" }]
+    ```
+
+    Example with multiple conversational turns:
+
+    ```json
+    [
+      { "role": "user", "content": "Hello there." },
+      { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
+      { "role": "user", "content": "Can you explain LLMs in plain English?" }
+    ]
+    ```
+
+    Example with a partially-filled response from Claude:
+
+    ```json
+    [
+      {
+        "role": "user",
+        "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
+      },
+      { "role": "assistant", "content": "The best answer is (" }
+    ]
+    ```
+
+    Each input message `content` may be either a single `string` or an array of
+    content blocks, where each block has a specific `type`. Using a `string` for
+    `content` is shorthand for an array of one content block of type `"text"`. The
+    following input messages are equivalent:
+
+    ```json
+    { "role": "user", "content": "Hello, Claude" }
+    ```
+
+    ```json
+    { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
+    ```
+
+    Starting with Claude 3 models, you can also send image content blocks:
+
+    ```json
+    {
+      "role": "user",
+      "content": [
+        {
+          "type": "image",
+          "source": {
+            "type": "base64",
+            "media_type": "image/jpeg",
+            "data": "/9j/4AAQSkZJRg..."
+          }
+        },
+        { "type": "text", "text": "What is in this image?" }
+      ]
+    }
+    ```
+
+    We currently support the `base64` source type for images, and the `image/jpeg`,
+    `image/png`, `image/gif`, and `image/webp` media types.
+
+    See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for
+    more input examples.
+
+    Note that if you want to include a
+    [system prompt](https://docs.anthropic.com/en/docs/system-prompts), you can use
+    the top-level `system` parameter — there is no `"system"` role for input
+    messages in the Messages API.
+    """
+
+    model: Required[ModelParam]
+    """
+    The model that will complete your prompt.\n\nSee
+    [models](https://docs.anthropic.com/en/docs/models-overview) for additional
+    details and options.
+    """
+
+    metadata: MetadataParam
+    """An object describing metadata about the request."""
+
+    stop_sequences: List[str]
+    """Custom text sequences that will cause the model to stop generating.
+
+    Our models will normally stop when they have naturally completed their turn,
+    which will result in a response `stop_reason` of `"end_turn"`.
+
+    If you want the model to stop generating when it encounters custom strings of
+    text, you can use the `stop_sequences` parameter. If the model encounters one of
+    the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
+    and the response `stop_sequence` value will contain the matched stop sequence.
+    """
+
+    system: Union[str, Iterable[TextBlockParam]]
+    """System prompt.
+
+    A system prompt is a way of providing context and instructions to Claude, such
+    as specifying a particular goal or role. See our
+    [guide to system prompts](https://docs.anthropic.com/en/docs/system-prompts).
+    """
+
+    temperature: float
+    """Amount of randomness injected into the response.
+
+    Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
+    for analytical / multiple choice, and closer to `1.0` for creative and
+    generative tasks.
+
+    Note that even with `temperature` of `0.0`, the results will not be fully
+    deterministic.
+    """
+
+    thinking: ThinkingConfigParam
+    """Configuration for enabling Claude's extended thinking.
+
+    When enabled, responses include `thinking` content blocks showing Claude's
+    thinking process before the final answer. Requires a minimum budget of 1,024
+    tokens and counts towards your `max_tokens` limit.
+
+    See
+    [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+    for details.
+    """
+
+    tool_choice: ToolChoiceParam
+    """How the model should use the provided tools.
+
+    The model can use a specific tool, any available tool, decide by itself, or not
+    use tools at all.
+    """
+
+    tools: Iterable[ToolUnionParam]
+    """Definitions of tools that the model may use.
+
+    If you include `tools` in your API request, the model may return `tool_use`
+    content blocks that represent the model's use of those tools. You can then run
+    those tools using the tool input generated by the model and then optionally
+    return results back to the model using `tool_result` content blocks.
+
+    Each tool definition includes:
+
+    - `name`: Name of the tool.
+    - `description`: Optional, but strongly-recommended description of the tool.
+    - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
+      tool `input` shape that the model will produce in `tool_use` output content
+      blocks.
+
+    For example, if you defined `tools` as:
+
+    ```json
+    [
+      {
+        "name": "get_stock_price",
+        "description": "Get the current stock price for a given ticker symbol.",
+        "input_schema": {
+          "type": "object",
+          "properties": {
+            "ticker": {
+              "type": "string",
+              "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
+            }
+          },
+          "required": ["ticker"]
+        }
+      }
+    ]
+    ```
+
+    And then asked the model "What's the S&P 500 at today?", the model might produce
+    `tool_use` content blocks in the response like this:
+
+    ```json
+    [
+      {
+        "type": "tool_use",
+        "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "name": "get_stock_price",
+        "input": { "ticker": "^GSPC" }
+      }
+    ]
+    ```
+
+    You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
+    input, and return the following back to the model in a subsequent `user`
+    message:
+
+    ```json
+    [
+      {
+        "type": "tool_result",
+        "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
+        "content": "259.75 USD"
+      }
+    ]
+    ```
+
+    Tools can be used for workflows that include running client-side tools and
+    functions, or more generally whenever you want the model to produce a particular
+    JSON structure of output.
+
+    See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details.
+    """
+
+    top_k: int
+    """Only sample from the top K options for each subsequent token.
+
+    Used to remove "long tail" low probability responses.
+    [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
+
+    Recommended for advanced use cases only. You usually only need to use
+    `temperature`.
+    """
+
+    top_p: float
+    """Use nucleus sampling.
+
+    In nucleus sampling, we compute the cumulative distribution over all the options
+    for each subsequent token in decreasing probability order and cut it off once it
+    reaches a particular probability specified by `top_p`. You should either alter
+    `temperature` or `top_p`, but not both.
+
+    Recommended for advanced use cases only. You usually only need to use
+    `temperature`.
+    """
+
+
+Metadata: TypeAlias = MetadataParam
+"""This is deprecated, `MetadataParam` should be used instead"""
+
+ToolChoice: TypeAlias = ToolChoiceParam
+"""This is deprecated, `ToolChoiceParam` should be used instead"""
+
+ToolChoiceToolChoiceAuto: TypeAlias = ToolChoiceAutoParam
+"""This is deprecated, `ToolChoiceAutoParam` should be used instead"""
+
+ToolChoiceToolChoiceAny: TypeAlias = ToolChoiceAnyParam
+"""This is deprecated, `ToolChoiceAnyParam` should be used instead"""
+
+ToolChoiceToolChoiceTool: TypeAlias = ToolChoiceToolParam
+"""This is deprecated, `ToolChoiceToolParam` should be used instead"""
+
+
+class MessageCreateParamsNonStreaming(MessageCreateParamsBase, total=False):
+    stream: Literal[False]
+    """Whether to incrementally stream the response using server-sent events.
+
+    See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+    details.
+    """
+
+
+class MessageCreateParamsStreaming(MessageCreateParamsBase):
+    stream: Required[Literal[True]]
+    """Whether to incrementally stream the response using server-sent events.
+
+    See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for
+    details.
+    """
+
+
+MessageCreateParams = Union[MessageCreateParamsNonStreaming, MessageCreateParamsStreaming]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_delta_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_delta_event.py
new file mode 100644
index 00000000..3803629a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_delta_event.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .raw_message_delta_event import RawMessageDeltaEvent
+
+__all__ = ["MessageDeltaEvent"]
+
+MessageDeltaEvent = RawMessageDeltaEvent
+"""The RawMessageDeltaEvent type should be used instead"""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_delta_usage.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_delta_usage.py
new file mode 100644
index 00000000..e4321be4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_delta_usage.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .._models import BaseModel
+
+__all__ = ["MessageDeltaUsage"]
+
+
+class MessageDeltaUsage(BaseModel):
+    output_tokens: int
+    """The cumulative number of output tokens which were used."""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_param.py
new file mode 100644
index 00000000..3c054395
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_param.py
@@ -0,0 +1,39 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable
+from typing_extensions import Literal, Required, TypedDict
+
+from .content_block import ContentBlock
+from .text_block_param import TextBlockParam
+from .image_block_param import ImageBlockParam
+from .document_block_param import DocumentBlockParam
+from .thinking_block_param import ThinkingBlockParam
+from .tool_use_block_param import ToolUseBlockParam
+from .tool_result_block_param import ToolResultBlockParam
+from .redacted_thinking_block_param import RedactedThinkingBlockParam
+
+__all__ = ["MessageParam"]
+
+
+class MessageParam(TypedDict, total=False):
+    content: Required[
+        Union[
+            str,
+            Iterable[
+                Union[
+                    TextBlockParam,
+                    ImageBlockParam,
+                    ToolUseBlockParam,
+                    ToolResultBlockParam,
+                    DocumentBlockParam,
+                    ThinkingBlockParam,
+                    RedactedThinkingBlockParam,
+                    ContentBlock,
+                ]
+            ],
+        ]
+    ]
+
+    role: Required[Literal["user", "assistant"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_start_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_start_event.py
new file mode 100644
index 00000000..c210d3ad
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_start_event.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .raw_message_start_event import RawMessageStartEvent
+
+__all__ = ["MessageStartEvent"]
+
+MessageStartEvent = RawMessageStartEvent
+"""The RawMessageStartEvent type should be used instead"""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_stop_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_stop_event.py
new file mode 100644
index 00000000..1076a62c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_stop_event.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .raw_message_stop_event import RawMessageStopEvent
+
+__all__ = ["MessageStopEvent"]
+
+MessageStopEvent = RawMessageStopEvent
+"""The RawMessageStopEvent type should be used instead"""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_stream_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_stream_event.py
new file mode 100644
index 00000000..ec5a0125
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_stream_event.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .raw_message_stream_event import RawMessageStreamEvent
+
+__all__ = ["MessageStreamEvent"]
+
+MessageStreamEvent = RawMessageStreamEvent
+"""The RawMessageStreamEvent type should be used instead"""
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/message_tokens_count.py b/.venv/lib/python3.12/site-packages/anthropic/types/message_tokens_count.py
new file mode 100644
index 00000000..d570019f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/message_tokens_count.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from .._models import BaseModel
+
+__all__ = ["MessageTokensCount"]
+
+
+class MessageTokensCount(BaseModel):
+    input_tokens: int
+    """
+    The total number of tokens across the provided list of messages, system prompt,
+    and tools.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/__init__.py
new file mode 100644
index 00000000..25d311da
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/__init__.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .message_batch import MessageBatch as MessageBatch
+from .batch_list_params import BatchListParams as BatchListParams
+from .batch_create_params import BatchCreateParams as BatchCreateParams
+from .message_batch_result import MessageBatchResult as MessageBatchResult
+from .deleted_message_batch import DeletedMessageBatch as DeletedMessageBatch
+from .message_batch_errored_result import MessageBatchErroredResult as MessageBatchErroredResult
+from .message_batch_expired_result import MessageBatchExpiredResult as MessageBatchExpiredResult
+from .message_batch_request_counts import MessageBatchRequestCounts as MessageBatchRequestCounts
+from .message_batch_canceled_result import MessageBatchCanceledResult as MessageBatchCanceledResult
+from .message_batch_succeeded_result import MessageBatchSucceededResult as MessageBatchSucceededResult
+from .message_batch_individual_response import MessageBatchIndividualResponse as MessageBatchIndividualResponse
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_create_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_create_params.py
new file mode 100644
index 00000000..a82a5ff0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_create_params.py
@@ -0,0 +1,36 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable
+from typing_extensions import Required, TypedDict
+
+from ..message_create_params import MessageCreateParamsNonStreaming
+
+__all__ = ["BatchCreateParams", "Request"]
+
+
+class BatchCreateParams(TypedDict, total=False):
+    requests: Required[Iterable[Request]]
+    """List of requests for prompt completion.
+
+    Each is an individual request to create a Message.
+    """
+
+
+class Request(TypedDict, total=False):
+    custom_id: Required[str]
+    """Developer-provided ID created for each request in a Message Batch.
+
+    Useful for matching results to requests, as results may be given out of request
+    order.
+
+    Must be unique for each request within the Message Batch.
+    """
+
+    params: Required[MessageCreateParamsNonStreaming]
+    """Messages API creation parameters for the individual request.
+
+    See the [Messages API reference](/en/api/messages) for full documentation on
+    available parameters.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_list_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_list_params.py
new file mode 100644
index 00000000..7b290a77
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/batch_list_params.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["BatchListParams"]
+
+
+class BatchListParams(TypedDict, total=False):
+    after_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately after this object.
+    """
+
+    before_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately before this object.
+    """
+
+    limit: int
+    """Number of items to return per page.
+
+    Defaults to `20`. Ranges from `1` to `1000`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/deleted_message_batch.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/deleted_message_batch.py
new file mode 100644
index 00000000..7a6c321e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/deleted_message_batch.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["DeletedMessageBatch"]
+
+
+class DeletedMessageBatch(BaseModel):
+    id: str
+    """ID of the Message Batch."""
+
+    type: Literal["message_batch_deleted"]
+    """Deleted object type.
+
+    For Message Batches, this is always `"message_batch_deleted"`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch.py
new file mode 100644
index 00000000..a03e73e1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch.py
@@ -0,0 +1,77 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+from .message_batch_request_counts import MessageBatchRequestCounts
+
+__all__ = ["MessageBatch"]
+
+
+class MessageBatch(BaseModel):
+    id: str
+    """Unique object identifier.
+
+    The format and length of IDs may change over time.
+    """
+
+    archived_at: Optional[datetime] = None
+    """
+    RFC 3339 datetime string representing the time at which the Message Batch was
+    archived and its results became unavailable.
+    """
+
+    cancel_initiated_at: Optional[datetime] = None
+    """
+    RFC 3339 datetime string representing the time at which cancellation was
+    initiated for the Message Batch. Specified only if cancellation was initiated.
+    """
+
+    created_at: datetime
+    """
+    RFC 3339 datetime string representing the time at which the Message Batch was
+    created.
+    """
+
+    ended_at: Optional[datetime] = None
+    """
+    RFC 3339 datetime string representing the time at which processing for the
+    Message Batch ended. Specified only once processing ends.
+
+    Processing ends when every request in a Message Batch has either succeeded,
+    errored, canceled, or expired.
+    """
+
+    expires_at: datetime
+    """
+    RFC 3339 datetime string representing the time at which the Message Batch will
+    expire and end processing, which is 24 hours after creation.
+    """
+
+    processing_status: Literal["in_progress", "canceling", "ended"]
+    """Processing status of the Message Batch."""
+
+    request_counts: MessageBatchRequestCounts
+    """Tallies requests within the Message Batch, categorized by their status.
+
+    Requests start as `processing` and move to one of the other statuses only once
+    processing of the entire batch ends. The sum of all values always matches the
+    total number of requests in the batch.
+    """
+
+    results_url: Optional[str] = None
+    """URL to a `.jsonl` file containing the results of the Message Batch requests.
+
+    Specified only once processing ends.
+
+    Results in the file are not guaranteed to be in the same order as requests. Use
+    the `custom_id` field to match results to requests.
+    """
+
+    type: Literal["message_batch"]
+    """Object type.
+
+    For Message Batches, this is always `"message_batch"`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_canceled_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_canceled_result.py
new file mode 100644
index 00000000..9826aa91
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_canceled_result.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["MessageBatchCanceledResult"]
+
+
+class MessageBatchCanceledResult(BaseModel):
+    type: Literal["canceled"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_errored_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_errored_result.py
new file mode 100644
index 00000000..5f890bfd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_errored_result.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+from ..shared.error_response import ErrorResponse
+
+__all__ = ["MessageBatchErroredResult"]
+
+
+class MessageBatchErroredResult(BaseModel):
+    error: ErrorResponse
+
+    type: Literal["errored"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_expired_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_expired_result.py
new file mode 100644
index 00000000..ab9964e7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_expired_result.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["MessageBatchExpiredResult"]
+
+
+class MessageBatchExpiredResult(BaseModel):
+    type: Literal["expired"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_individual_response.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_individual_response.py
new file mode 100644
index 00000000..19d4f090
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_individual_response.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from ..._models import BaseModel
+from .message_batch_result import MessageBatchResult
+
+__all__ = ["MessageBatchIndividualResponse"]
+
+
+class MessageBatchIndividualResponse(BaseModel):
+    custom_id: str
+    """Developer-provided ID created for each request in a Message Batch.
+
+    Useful for matching results to requests, as results may be given out of request
+    order.
+
+    Must be unique for each request within the Message Batch.
+    """
+
+    result: MessageBatchResult
+    """Processing result for this request.
+
+    Contains a Message output if processing was successful, an error response if
+    processing failed, or the reason why processing was not attempted, such as
+    cancellation or expiration.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_request_counts.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_request_counts.py
new file mode 100644
index 00000000..04edc3c3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_request_counts.py
@@ -0,0 +1,35 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+
+from ..._models import BaseModel
+
+__all__ = ["MessageBatchRequestCounts"]
+
+
+class MessageBatchRequestCounts(BaseModel):
+    canceled: int
+    """Number of requests in the Message Batch that have been canceled.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
+
+    errored: int
+    """Number of requests in the Message Batch that encountered an error.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
+
+    expired: int
+    """Number of requests in the Message Batch that have expired.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
+
+    processing: int
+    """Number of requests in the Message Batch that are processing."""
+
+    succeeded: int
+    """Number of requests in the Message Batch that have completed successfully.
+
+    This is zero until processing of the entire Message Batch has ended.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_result.py
new file mode 100644
index 00000000..3186f2aa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_result.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from .message_batch_errored_result import MessageBatchErroredResult
+from .message_batch_expired_result import MessageBatchExpiredResult
+from .message_batch_canceled_result import MessageBatchCanceledResult
+from .message_batch_succeeded_result import MessageBatchSucceededResult
+
+__all__ = ["MessageBatchResult"]
+
+MessageBatchResult: TypeAlias = Annotated[
+    Union[
+        MessageBatchSucceededResult, MessageBatchErroredResult, MessageBatchCanceledResult, MessageBatchExpiredResult
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_succeeded_result.py b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_succeeded_result.py
new file mode 100644
index 00000000..1cc454a4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/messages/message_batch_succeeded_result.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..message import Message
+from ..._models import BaseModel
+
+__all__ = ["MessageBatchSucceededResult"]
+
+
+class MessageBatchSucceededResult(BaseModel):
+    message: Message
+
+    type: Literal["succeeded"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/metadata_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/metadata_param.py
new file mode 100644
index 00000000..b7bc1ea3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/metadata_param.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import TypedDict
+
+__all__ = ["MetadataParam"]
+
+
+class MetadataParam(TypedDict, total=False):
+    user_id: Optional[str]
+    """An external identifier for the user who is associated with the request.
+
+    This should be a uuid, hash value, or other opaque identifier. Anthropic may use
+    this id to help detect abuse. Do not include any identifying information such as
+    name, email address, or phone number.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/model.py b/.venv/lib/python3.12/site-packages/anthropic/types/model.py
new file mode 100644
index 00000000..02d40800
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/model.py
@@ -0,0 +1,25 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["Model"]
+
+Model: TypeAlias = Union[
+    Literal[
+        "claude-3-7-sonnet-latest",
+        "claude-3-7-sonnet-20250219",
+        "claude-3-5-haiku-latest",
+        "claude-3-5-haiku-20241022",
+        "claude-3-5-sonnet-latest",
+        "claude-3-5-sonnet-20241022",
+        "claude-3-5-sonnet-20240620",
+        "claude-3-opus-latest",
+        "claude-3-opus-20240229",
+        "claude-3-sonnet-20240229",
+        "claude-3-haiku-20240307",
+        "claude-2.1",
+        "claude-2.0",
+    ],
+    str,
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/model_info.py b/.venv/lib/python3.12/site-packages/anthropic/types/model_info.py
new file mode 100644
index 00000000..0e3945fe
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/model_info.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["ModelInfo"]
+
+
+class ModelInfo(BaseModel):
+    id: str
+    """Unique model identifier."""
+
+    created_at: datetime
+    """RFC 3339 datetime string representing the time at which the model was released.
+
+    May be set to an epoch value if the release date is unknown.
+    """
+
+    display_name: str
+    """A human-readable name for the model."""
+
+    type: Literal["model"]
+    """Object type.
+
+    For Models, this is always `"model"`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/model_list_params.py b/.venv/lib/python3.12/site-packages/anthropic/types/model_list_params.py
new file mode 100644
index 00000000..b16d22a3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/model_list_params.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["ModelListParams"]
+
+
+class ModelListParams(TypedDict, total=False):
+    after_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately after this object.
+    """
+
+    before_id: str
+    """ID of the object to use as a cursor for pagination.
+
+    When provided, returns the page of results immediately before this object.
+    """
+
+    limit: int
+    """Number of items to return per page.
+
+    Defaults to `20`. Ranges from `1` to `1000`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/model_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/model_param.py
new file mode 100644
index 00000000..bce6f522
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/model_param.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["ModelParam"]
+
+ModelParam: TypeAlias = Union[
+    Literal[
+        "claude-3-7-sonnet-latest",
+        "claude-3-7-sonnet-20250219",
+        "claude-3-5-haiku-latest",
+        "claude-3-5-haiku-20241022",
+        "claude-3-5-sonnet-latest",
+        "claude-3-5-sonnet-20241022",
+        "claude-3-5-sonnet-20240620",
+        "claude-3-opus-latest",
+        "claude-3-opus-20240229",
+        "claude-3-sonnet-20240229",
+        "claude-3-haiku-20240307",
+        "claude-2.1",
+        "claude-2.0",
+    ],
+    str,
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/plain_text_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/plain_text_source_param.py
new file mode 100644
index 00000000..a2a3b8de
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/plain_text_source_param.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["PlainTextSourceParam"]
+
+
+class PlainTextSourceParam(TypedDict, total=False):
+    data: Required[str]
+
+    media_type: Required[Literal["text/plain"]]
+
+    type: Required[Literal["text"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_delta_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_delta_event.py
new file mode 100644
index 00000000..5bdbf09a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_delta_event.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+from .text_delta import TextDelta
+from .thinking_delta import ThinkingDelta
+from .citations_delta import CitationsDelta
+from .signature_delta import SignatureDelta
+from .input_json_delta import InputJSONDelta
+
+__all__ = ["RawContentBlockDeltaEvent", "Delta"]
+
+Delta: TypeAlias = Annotated[
+    Union[TextDelta, InputJSONDelta, CitationsDelta, ThinkingDelta, SignatureDelta], PropertyInfo(discriminator="type")
+]
+
+
+class RawContentBlockDeltaEvent(BaseModel):
+    delta: Delta
+
+    index: int
+
+    type: Literal["content_block_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_start_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_start_event.py
new file mode 100644
index 00000000..bfbaa63d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_start_event.py
@@ -0,0 +1,25 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+from .text_block import TextBlock
+from .thinking_block import ThinkingBlock
+from .tool_use_block import ToolUseBlock
+from .redacted_thinking_block import RedactedThinkingBlock
+
+__all__ = ["RawContentBlockStartEvent", "ContentBlock"]
+
+ContentBlock: TypeAlias = Annotated[
+    Union[TextBlock, ToolUseBlock, ThinkingBlock, RedactedThinkingBlock], PropertyInfo(discriminator="type")
+]
+
+
+class RawContentBlockStartEvent(BaseModel):
+    content_block: ContentBlock
+
+    index: int
+
+    type: Literal["content_block_start"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_stop_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_stop_event.py
new file mode 100644
index 00000000..6241a8b2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/raw_content_block_stop_event.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["RawContentBlockStopEvent"]
+
+
+class RawContentBlockStopEvent(BaseModel):
+    index: int
+
+    type: Literal["content_block_stop"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_delta_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_delta_event.py
new file mode 100644
index 00000000..3dae1e0d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_delta_event.py
@@ -0,0 +1,39 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .message_delta_usage import MessageDeltaUsage
+
+__all__ = ["RawMessageDeltaEvent", "Delta"]
+
+
+class Delta(BaseModel):
+    stop_reason: Optional[Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]] = None
+
+    stop_sequence: Optional[str] = None
+
+
+class RawMessageDeltaEvent(BaseModel):
+    delta: Delta
+
+    type: Literal["message_delta"]
+
+    usage: MessageDeltaUsage
+    """Billing and rate-limit usage.
+
+    Anthropic's API bills and rate-limits by token counts, as tokens represent the
+    underlying cost to our systems.
+
+    Under the hood, the API transforms requests into a format suitable for the
+    model. The model's output then goes through a parsing stage before becoming an
+    API response. As a result, the token counts in `usage` will not match one-to-one
+    with the exact visible content of an API request or response.
+
+    For example, `output_tokens` will be non-zero, even for an empty string response
+    from Claude.
+
+    Total input tokens in a request is the summation of `input_tokens`,
+    `cache_creation_input_tokens`, and `cache_read_input_tokens`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_start_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_start_event.py
new file mode 100644
index 00000000..1b9e8904
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_start_event.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .message import Message
+from .._models import BaseModel
+
+__all__ = ["RawMessageStartEvent"]
+
+
+class RawMessageStartEvent(BaseModel):
+    message: Message
+
+    type: Literal["message_start"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stop_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stop_event.py
new file mode 100644
index 00000000..d40ccfe2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stop_event.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["RawMessageStopEvent"]
+
+
+class RawMessageStopEvent(BaseModel):
+    type: Literal["message_stop"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stream_event.py b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stream_event.py
new file mode 100644
index 00000000..728fbe88
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/raw_message_stream_event.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .raw_message_stop_event import RawMessageStopEvent
+from .raw_message_delta_event import RawMessageDeltaEvent
+from .raw_message_start_event import RawMessageStartEvent
+from .raw_content_block_stop_event import RawContentBlockStopEvent
+from .raw_content_block_delta_event import RawContentBlockDeltaEvent
+from .raw_content_block_start_event import RawContentBlockStartEvent
+
+__all__ = ["RawMessageStreamEvent"]
+
+RawMessageStreamEvent: TypeAlias = Annotated[
+    Union[
+        RawMessageStartEvent,
+        RawMessageDeltaEvent,
+        RawMessageStopEvent,
+        RawContentBlockStartEvent,
+        RawContentBlockDeltaEvent,
+        RawContentBlockStopEvent,
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block.py
new file mode 100644
index 00000000..4850b335
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["RedactedThinkingBlock"]
+
+
+class RedactedThinkingBlock(BaseModel):
+    data: str
+
+    type: Literal["redacted_thinking"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block_param.py
new file mode 100644
index 00000000..0933188c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/redacted_thinking_block_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["RedactedThinkingBlockParam"]
+
+
+class RedactedThinkingBlockParam(TypedDict, total=False):
+    data: Required[str]
+
+    type: Required[Literal["redacted_thinking"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/__init__.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/__init__.py
new file mode 100644
index 00000000..178643b6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/__init__.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .error_object import ErrorObject as ErrorObject
+from .billing_error import BillingError as BillingError
+from .error_response import ErrorResponse as ErrorResponse
+from .not_found_error import NotFoundError as NotFoundError
+from .api_error_object import APIErrorObject as APIErrorObject
+from .overloaded_error import OverloadedError as OverloadedError
+from .permission_error import PermissionError as PermissionError
+from .rate_limit_error import RateLimitError as RateLimitError
+from .authentication_error import AuthenticationError as AuthenticationError
+from .gateway_timeout_error import GatewayTimeoutError as GatewayTimeoutError
+from .invalid_request_error import InvalidRequestError as InvalidRequestError
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/api_error_object.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/api_error_object.py
new file mode 100644
index 00000000..dd92bead
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/api_error_object.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["APIErrorObject"]
+
+
+class APIErrorObject(BaseModel):
+    message: str
+
+    type: Literal["api_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/authentication_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/authentication_error.py
new file mode 100644
index 00000000..f777f5c8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/authentication_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["AuthenticationError"]
+
+
+class AuthenticationError(BaseModel):
+    message: str
+
+    type: Literal["authentication_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/billing_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/billing_error.py
new file mode 100644
index 00000000..26be12bb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/billing_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["BillingError"]
+
+
+class BillingError(BaseModel):
+    message: str
+
+    type: Literal["billing_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/error_object.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/error_object.py
new file mode 100644
index 00000000..086db503
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/error_object.py
@@ -0,0 +1,32 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from ..._utils import PropertyInfo
+from .billing_error import BillingError
+from .not_found_error import NotFoundError
+from .api_error_object import APIErrorObject
+from .overloaded_error import OverloadedError
+from .permission_error import PermissionError
+from .rate_limit_error import RateLimitError
+from .authentication_error import AuthenticationError
+from .gateway_timeout_error import GatewayTimeoutError
+from .invalid_request_error import InvalidRequestError
+
+__all__ = ["ErrorObject"]
+
+ErrorObject: TypeAlias = Annotated[
+    Union[
+        InvalidRequestError,
+        AuthenticationError,
+        BillingError,
+        PermissionError,
+        NotFoundError,
+        RateLimitError,
+        GatewayTimeoutError,
+        APIErrorObject,
+        OverloadedError,
+    ],
+    PropertyInfo(discriminator="type"),
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/error_response.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/error_response.py
new file mode 100644
index 00000000..97034923
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/error_response.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+from .error_object import ErrorObject
+
+__all__ = ["ErrorResponse"]
+
+
+class ErrorResponse(BaseModel):
+    error: ErrorObject
+
+    type: Literal["error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/gateway_timeout_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/gateway_timeout_error.py
new file mode 100644
index 00000000..908aa12f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/gateway_timeout_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["GatewayTimeoutError"]
+
+
+class GatewayTimeoutError(BaseModel):
+    message: str
+
+    type: Literal["timeout_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/invalid_request_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/invalid_request_error.py
new file mode 100644
index 00000000..ee5befc0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/invalid_request_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["InvalidRequestError"]
+
+
+class InvalidRequestError(BaseModel):
+    message: str
+
+    type: Literal["invalid_request_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/not_found_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/not_found_error.py
new file mode 100644
index 00000000..43e826fb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/not_found_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["NotFoundError"]
+
+
+class NotFoundError(BaseModel):
+    message: str
+
+    type: Literal["not_found_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/overloaded_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/overloaded_error.py
new file mode 100644
index 00000000..74ee8373
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/overloaded_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["OverloadedError"]
+
+
+class OverloadedError(BaseModel):
+    message: str
+
+    type: Literal["overloaded_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/permission_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/permission_error.py
new file mode 100644
index 00000000..48eb3546
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/permission_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["PermissionError"]
+
+
+class PermissionError(BaseModel):
+    message: str
+
+    type: Literal["permission_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/shared/rate_limit_error.py b/.venv/lib/python3.12/site-packages/anthropic/types/shared/rate_limit_error.py
new file mode 100644
index 00000000..3fa065ac
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/shared/rate_limit_error.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["RateLimitError"]
+
+
+class RateLimitError(BaseModel):
+    message: str
+
+    type: Literal["rate_limit_error"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/signature_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/signature_delta.py
new file mode 100644
index 00000000..55d15189
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/signature_delta.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["SignatureDelta"]
+
+
+class SignatureDelta(BaseModel):
+    signature: str
+
+    type: Literal["signature_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/text_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/text_block.py
new file mode 100644
index 00000000..ecdddb69
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/text_block.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .text_citation import TextCitation
+
+__all__ = ["TextBlock"]
+
+
+class TextBlock(BaseModel):
+    citations: Optional[List[TextCitation]] = None
+    """Citations supporting the text block.
+
+    The type of citation returned will depend on the type of document being cited.
+    Citing a PDF results in `page_location`, plain text results in `char_location`,
+    and content document results in `content_block_location`.
+    """
+
+    text: str
+
+    type: Literal["text"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/text_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/text_block_param.py
new file mode 100644
index 00000000..92151733
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/text_block_param.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable, Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .text_citation_param import TextCitationParam
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["TextBlockParam"]
+
+
+class TextBlockParam(TypedDict, total=False):
+    text: Required[str]
+
+    type: Required[Literal["text"]]
+
+    cache_control: Optional[CacheControlEphemeralParam]
+
+    citations: Optional[Iterable[TextCitationParam]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/text_citation.py b/.venv/lib/python3.12/site-packages/anthropic/types/text_citation.py
new file mode 100644
index 00000000..159771ae
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/text_citation.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from .._utils import PropertyInfo
+from .citation_char_location import CitationCharLocation
+from .citation_page_location import CitationPageLocation
+from .citation_content_block_location import CitationContentBlockLocation
+
+__all__ = ["TextCitation"]
+
+TextCitation: TypeAlias = Annotated[
+    Union[CitationCharLocation, CitationPageLocation, CitationContentBlockLocation], PropertyInfo(discriminator="type")
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/text_citation_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/text_citation_param.py
new file mode 100644
index 00000000..8e988141
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/text_citation_param.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .citation_char_location_param import CitationCharLocationParam
+from .citation_page_location_param import CitationPageLocationParam
+from .citation_content_block_location_param import CitationContentBlockLocationParam
+
+__all__ = ["TextCitationParam"]
+
+TextCitationParam: TypeAlias = Union[
+    CitationCharLocationParam, CitationPageLocationParam, CitationContentBlockLocationParam
+]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/text_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/text_delta.py
new file mode 100644
index 00000000..7ce96491
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/text_delta.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["TextDelta"]
+
+
+class TextDelta(BaseModel):
+    text: str
+
+    type: Literal["text_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/thinking_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_block.py
new file mode 100644
index 00000000..7f98b500
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_block.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["ThinkingBlock"]
+
+
+class ThinkingBlock(BaseModel):
+    signature: str
+
+    thinking: str
+
+    type: Literal["thinking"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/thinking_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_block_param.py
new file mode 100644
index 00000000..d310c7f6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_block_param.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ThinkingBlockParam"]
+
+
+class ThinkingBlockParam(TypedDict, total=False):
+    signature: Required[str]
+
+    thinking: Required[str]
+
+    type: Required[Literal["thinking"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_disabled_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_disabled_param.py
new file mode 100644
index 00000000..23b5fbad
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_disabled_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ThinkingConfigDisabledParam"]
+
+
+class ThinkingConfigDisabledParam(TypedDict, total=False):
+    type: Required[Literal["disabled"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_enabled_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_enabled_param.py
new file mode 100644
index 00000000..46b54892
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_enabled_param.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ThinkingConfigEnabledParam"]
+
+
+class ThinkingConfigEnabledParam(TypedDict, total=False):
+    budget_tokens: Required[int]
+    """Determines how many tokens Claude can use for its internal reasoning process.
+
+    Larger budgets can enable more thorough analysis for complex problems, improving
+    response quality.
+
+    Must be ≥1024 and less than `max_tokens`.
+
+    See
+    [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking)
+    for details.
+    """
+
+    type: Required[Literal["enabled"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_param.py
new file mode 100644
index 00000000..0c1f9173
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_config_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .thinking_config_enabled_param import ThinkingConfigEnabledParam
+from .thinking_config_disabled_param import ThinkingConfigDisabledParam
+
+__all__ = ["ThinkingConfigParam"]
+
+ThinkingConfigParam: TypeAlias = Union[ThinkingConfigEnabledParam, ThinkingConfigDisabledParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/thinking_delta.py b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_delta.py
new file mode 100644
index 00000000..fb79933c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/thinking_delta.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["ThinkingDelta"]
+
+
+class ThinkingDelta(BaseModel):
+    thinking: str
+
+    type: Literal["thinking_delta"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_bash_20250124_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_bash_20250124_param.py
new file mode 100644
index 00000000..6c8ff0fc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_bash_20250124_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["ToolBash20250124Param"]
+
+
+class ToolBash20250124Param(TypedDict, total=False):
+    name: Required[Literal["bash"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["bash_20250124"]]
+
+    cache_control: Optional[CacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_any_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_any_param.py
new file mode 100644
index 00000000..a0a566ea
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_any_param.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ToolChoiceAnyParam"]
+
+
+class ToolChoiceAnyParam(TypedDict, total=False):
+    type: Required[Literal["any"]]
+
+    disable_parallel_tool_use: bool
+    """Whether to disable parallel tool use.
+
+    Defaults to `false`. If set to `true`, the model will output exactly one tool
+    use.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_auto_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_auto_param.py
new file mode 100644
index 00000000..456f675c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_auto_param.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ToolChoiceAutoParam"]
+
+
+class ToolChoiceAutoParam(TypedDict, total=False):
+    type: Required[Literal["auto"]]
+
+    disable_parallel_tool_use: bool
+    """Whether to disable parallel tool use.
+
+    Defaults to `false`. If set to `true`, the model will output at most one tool
+    use.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_none_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_none_param.py
new file mode 100644
index 00000000..1e2e68a7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_none_param.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ToolChoiceNoneParam"]
+
+
+class ToolChoiceNoneParam(TypedDict, total=False):
+    type: Required[Literal["none"]]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_param.py
new file mode 100644
index 00000000..868277d4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_param.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .tool_choice_any_param import ToolChoiceAnyParam
+from .tool_choice_auto_param import ToolChoiceAutoParam
+from .tool_choice_none_param import ToolChoiceNoneParam
+from .tool_choice_tool_param import ToolChoiceToolParam
+
+__all__ = ["ToolChoiceParam"]
+
+ToolChoiceParam: TypeAlias = Union[ToolChoiceAutoParam, ToolChoiceAnyParam, ToolChoiceToolParam, ToolChoiceNoneParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_tool_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_tool_param.py
new file mode 100644
index 00000000..aeec9966
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_choice_tool_param.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ToolChoiceToolParam"]
+
+
+class ToolChoiceToolParam(TypedDict, total=False):
+    name: Required[str]
+    """The name of the tool to use."""
+
+    type: Required[Literal["tool"]]
+
+    disable_parallel_tool_use: bool
+    """Whether to disable parallel tool use.
+
+    Defaults to `false`. If set to `true`, the model will output exactly one tool
+    use.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_param.py
new file mode 100644
index 00000000..a01a014e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_param.py
@@ -0,0 +1,48 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Union, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .._models import set_pydantic_config
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["ToolParam", "InputSchema"]
+
+
+class InputSchemaTyped(TypedDict, total=False):
+    type: Required[Literal["object"]]
+
+    properties: Optional[object]
+
+
+set_pydantic_config(InputSchemaTyped, {"extra": "allow"})
+
+InputSchema: TypeAlias = Union[InputSchemaTyped, Dict[str, object]]
+
+
+class ToolParam(TypedDict, total=False):
+    input_schema: Required[InputSchema]
+    """[JSON schema](https://json-schema.org/draft/2020-12) for this tool's input.
+
+    This defines the shape of the `input` that your tool accepts and that the model
+    will produce.
+    """
+
+    name: Required[str]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    cache_control: Optional[CacheControlEphemeralParam]
+
+    description: str
+    """Description of what this tool does.
+
+    Tool descriptions should be as detailed as possible. The more information that
+    the model has about what the tool is and how to use it, the better it will
+    perform. You can use natural language descriptions to reinforce important
+    aspects of the tool input JSON schema.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_result_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_result_block_param.py
new file mode 100644
index 00000000..b6ca8aa9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_result_block_param.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .text_block_param import TextBlockParam
+from .image_block_param import ImageBlockParam
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["ToolResultBlockParam", "Content"]
+
+Content: TypeAlias = Union[TextBlockParam, ImageBlockParam]
+
+
+class ToolResultBlockParam(TypedDict, total=False):
+    tool_use_id: Required[str]
+
+    type: Required[Literal["tool_result"]]
+
+    cache_control: Optional[CacheControlEphemeralParam]
+
+    content: Union[str, Iterable[Content]]
+
+    is_error: bool
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_text_editor_20250124_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_text_editor_20250124_param.py
new file mode 100644
index 00000000..94f63102
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_text_editor_20250124_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["ToolTextEditor20250124Param"]
+
+
+class ToolTextEditor20250124Param(TypedDict, total=False):
+    name: Required[Literal["str_replace_editor"]]
+    """Name of the tool.
+
+    This is how the tool will be called by the model and in tool_use blocks.
+    """
+
+    type: Required[Literal["text_editor_20250124"]]
+
+    cache_control: Optional[CacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_union_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_union_param.py
new file mode 100644
index 00000000..6c02090e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_union_param.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import TypeAlias
+
+from .tool_param import ToolParam
+from .tool_bash_20250124_param import ToolBash20250124Param
+from .tool_text_editor_20250124_param import ToolTextEditor20250124Param
+
+__all__ = ["ToolUnionParam"]
+
+ToolUnionParam: TypeAlias = Union[ToolParam, ToolBash20250124Param, ToolTextEditor20250124Param]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block.py
new file mode 100644
index 00000000..05514471
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["ToolUseBlock"]
+
+
+class ToolUseBlock(BaseModel):
+    id: str
+
+    input: object
+
+    name: str
+
+    type: Literal["tool_use"]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block_param.py
new file mode 100644
index 00000000..cc285079
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/tool_use_block_param.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, TypedDict
+
+from .cache_control_ephemeral_param import CacheControlEphemeralParam
+
+__all__ = ["ToolUseBlockParam"]
+
+
+class ToolUseBlockParam(TypedDict, total=False):
+    id: Required[str]
+
+    input: Required[object]
+
+    name: Required[str]
+
+    type: Required[Literal["tool_use"]]
+
+    cache_control: Optional[CacheControlEphemeralParam]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/url_image_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/url_image_source_param.py
new file mode 100644
index 00000000..852b8eee
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/url_image_source_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["URLImageSourceParam"]
+
+
+class URLImageSourceParam(TypedDict, total=False):
+    type: Required[Literal["url"]]
+
+    url: Required[str]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/url_pdf_source_param.py b/.venv/lib/python3.12/site-packages/anthropic/types/url_pdf_source_param.py
new file mode 100644
index 00000000..b5321d56
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/url_pdf_source_param.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["URLPDFSourceParam"]
+
+
+class URLPDFSourceParam(TypedDict, total=False):
+    type: Required[Literal["url"]]
+
+    url: Required[str]
diff --git a/.venv/lib/python3.12/site-packages/anthropic/types/usage.py b/.venv/lib/python3.12/site-packages/anthropic/types/usage.py
new file mode 100644
index 00000000..b4f817bd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anthropic/types/usage.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from .._models import BaseModel
+
+__all__ = ["Usage"]
+
+
+class Usage(BaseModel):
+    cache_creation_input_tokens: Optional[int] = None
+    """The number of input tokens used to create the cache entry."""
+
+    cache_read_input_tokens: Optional[int] = None
+    """The number of input tokens read from the cache."""
+
+    input_tokens: int
+    """The number of input tokens which were used."""
+
+    output_tokens: int
+    """The number of output tokens which were used."""