mirascope 1.22.4__py3-none-any.whl → 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mirascope/__init__.py +5 -50
- mirascope/_stubs.py +384 -0
- mirascope/_utils.py +34 -0
- mirascope/api/__init__.py +14 -0
- mirascope/api/_generated/README.md +207 -0
- mirascope/api/_generated/__init__.py +444 -0
- mirascope/api/_generated/annotations/__init__.py +33 -0
- mirascope/api/_generated/annotations/client.py +506 -0
- mirascope/api/_generated/annotations/raw_client.py +1414 -0
- mirascope/api/_generated/annotations/types/__init__.py +31 -0
- mirascope/api/_generated/annotations/types/annotations_create_request_label.py +5 -0
- mirascope/api/_generated/annotations/types/annotations_create_response.py +48 -0
- mirascope/api/_generated/annotations/types/annotations_create_response_label.py +5 -0
- mirascope/api/_generated/annotations/types/annotations_get_response.py +48 -0
- mirascope/api/_generated/annotations/types/annotations_get_response_label.py +5 -0
- mirascope/api/_generated/annotations/types/annotations_list_request_label.py +5 -0
- mirascope/api/_generated/annotations/types/annotations_list_response.py +21 -0
- mirascope/api/_generated/annotations/types/annotations_list_response_annotations_item.py +50 -0
- mirascope/api/_generated/annotations/types/annotations_list_response_annotations_item_label.py +5 -0
- mirascope/api/_generated/annotations/types/annotations_update_request_label.py +5 -0
- mirascope/api/_generated/annotations/types/annotations_update_response.py +48 -0
- mirascope/api/_generated/annotations/types/annotations_update_response_label.py +5 -0
- mirascope/api/_generated/api_keys/__init__.py +17 -0
- mirascope/api/_generated/api_keys/client.py +530 -0
- mirascope/api/_generated/api_keys/raw_client.py +1236 -0
- mirascope/api/_generated/api_keys/types/__init__.py +15 -0
- mirascope/api/_generated/api_keys/types/api_keys_create_response.py +28 -0
- mirascope/api/_generated/api_keys/types/api_keys_get_response.py +27 -0
- mirascope/api/_generated/api_keys/types/api_keys_list_all_for_org_response_item.py +40 -0
- mirascope/api/_generated/api_keys/types/api_keys_list_response_item.py +27 -0
- mirascope/api/_generated/client.py +211 -0
- mirascope/api/_generated/core/__init__.py +52 -0
- mirascope/api/_generated/core/api_error.py +23 -0
- mirascope/api/_generated/core/client_wrapper.py +46 -0
- mirascope/api/_generated/core/datetime_utils.py +28 -0
- mirascope/api/_generated/core/file.py +67 -0
- mirascope/api/_generated/core/force_multipart.py +16 -0
- mirascope/api/_generated/core/http_client.py +543 -0
- mirascope/api/_generated/core/http_response.py +55 -0
- mirascope/api/_generated/core/jsonable_encoder.py +100 -0
- mirascope/api/_generated/core/pydantic_utilities.py +255 -0
- mirascope/api/_generated/core/query_encoder.py +58 -0
- mirascope/api/_generated/core/remove_none_from_dict.py +11 -0
- mirascope/api/_generated/core/request_options.py +35 -0
- mirascope/api/_generated/core/serialization.py +276 -0
- mirascope/api/_generated/docs/__init__.py +4 -0
- mirascope/api/_generated/docs/client.py +91 -0
- mirascope/api/_generated/docs/raw_client.py +178 -0
- mirascope/api/_generated/environment.py +9 -0
- mirascope/api/_generated/environments/__init__.py +23 -0
- mirascope/api/_generated/environments/client.py +649 -0
- mirascope/api/_generated/environments/raw_client.py +1567 -0
- mirascope/api/_generated/environments/types/__init__.py +25 -0
- mirascope/api/_generated/environments/types/environments_create_response.py +24 -0
- mirascope/api/_generated/environments/types/environments_get_analytics_response.py +60 -0
- mirascope/api/_generated/environments/types/environments_get_analytics_response_top_functions_item.py +24 -0
- mirascope/api/_generated/environments/types/environments_get_analytics_response_top_models_item.py +22 -0
- mirascope/api/_generated/environments/types/environments_get_response.py +24 -0
- mirascope/api/_generated/environments/types/environments_list_response_item.py +24 -0
- mirascope/api/_generated/environments/types/environments_update_response.py +24 -0
- mirascope/api/_generated/errors/__init__.py +25 -0
- mirascope/api/_generated/errors/bad_request_error.py +14 -0
- mirascope/api/_generated/errors/conflict_error.py +14 -0
- mirascope/api/_generated/errors/forbidden_error.py +11 -0
- mirascope/api/_generated/errors/internal_server_error.py +10 -0
- mirascope/api/_generated/errors/not_found_error.py +11 -0
- mirascope/api/_generated/errors/payment_required_error.py +15 -0
- mirascope/api/_generated/errors/service_unavailable_error.py +14 -0
- mirascope/api/_generated/errors/too_many_requests_error.py +15 -0
- mirascope/api/_generated/errors/unauthorized_error.py +11 -0
- mirascope/api/_generated/functions/__init__.py +39 -0
- mirascope/api/_generated/functions/client.py +647 -0
- mirascope/api/_generated/functions/raw_client.py +1890 -0
- mirascope/api/_generated/functions/types/__init__.py +53 -0
- mirascope/api/_generated/functions/types/functions_create_request_dependencies_value.py +20 -0
- mirascope/api/_generated/functions/types/functions_create_response.py +37 -0
- mirascope/api/_generated/functions/types/functions_create_response_dependencies_value.py +20 -0
- mirascope/api/_generated/functions/types/functions_find_by_hash_response.py +39 -0
- mirascope/api/_generated/functions/types/functions_find_by_hash_response_dependencies_value.py +20 -0
- mirascope/api/_generated/functions/types/functions_get_by_env_response.py +53 -0
- mirascope/api/_generated/functions/types/functions_get_by_env_response_dependencies_value.py +22 -0
- mirascope/api/_generated/functions/types/functions_get_response.py +37 -0
- mirascope/api/_generated/functions/types/functions_get_response_dependencies_value.py +20 -0
- mirascope/api/_generated/functions/types/functions_list_by_env_response.py +25 -0
- mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item.py +56 -0
- mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item_dependencies_value.py +22 -0
- mirascope/api/_generated/functions/types/functions_list_response.py +21 -0
- mirascope/api/_generated/functions/types/functions_list_response_functions_item.py +41 -0
- mirascope/api/_generated/functions/types/functions_list_response_functions_item_dependencies_value.py +20 -0
- mirascope/api/_generated/health/__init__.py +7 -0
- mirascope/api/_generated/health/client.py +92 -0
- mirascope/api/_generated/health/raw_client.py +175 -0
- mirascope/api/_generated/health/types/__init__.py +8 -0
- mirascope/api/_generated/health/types/health_check_response.py +22 -0
- mirascope/api/_generated/health/types/health_check_response_status.py +5 -0
- mirascope/api/_generated/organization_invitations/__init__.py +33 -0
- mirascope/api/_generated/organization_invitations/client.py +546 -0
- mirascope/api/_generated/organization_invitations/raw_client.py +1519 -0
- mirascope/api/_generated/organization_invitations/types/__init__.py +53 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_accept_response.py +34 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_accept_response_role.py +7 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_request_role.py +7 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response.py +48 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response_role.py +7 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response_status.py +7 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response.py +48 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response_role.py +7 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response_status.py +7 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item.py +48 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item_role.py +7 -0
- mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item_status.py +7 -0
- mirascope/api/_generated/organization_memberships/__init__.py +19 -0
- mirascope/api/_generated/organization_memberships/client.py +302 -0
- mirascope/api/_generated/organization_memberships/raw_client.py +736 -0
- mirascope/api/_generated/organization_memberships/types/__init__.py +27 -0
- mirascope/api/_generated/organization_memberships/types/organization_memberships_list_response_item.py +33 -0
- mirascope/api/_generated/organization_memberships/types/organization_memberships_list_response_item_role.py +7 -0
- mirascope/api/_generated/organization_memberships/types/organization_memberships_update_request_role.py +7 -0
- mirascope/api/_generated/organization_memberships/types/organization_memberships_update_response.py +31 -0
- mirascope/api/_generated/organization_memberships/types/organization_memberships_update_response_role.py +7 -0
- mirascope/api/_generated/organizations/__init__.py +51 -0
- mirascope/api/_generated/organizations/client.py +869 -0
- mirascope/api/_generated/organizations/raw_client.py +2593 -0
- mirascope/api/_generated/organizations/types/__init__.py +71 -0
- mirascope/api/_generated/organizations/types/organizations_create_payment_intent_response.py +24 -0
- mirascope/api/_generated/organizations/types/organizations_create_response.py +26 -0
- mirascope/api/_generated/organizations/types/organizations_create_response_role.py +5 -0
- mirascope/api/_generated/organizations/types/organizations_get_response.py +26 -0
- mirascope/api/_generated/organizations/types/organizations_get_response_role.py +5 -0
- mirascope/api/_generated/organizations/types/organizations_list_response_item.py +26 -0
- mirascope/api/_generated/organizations/types/organizations_list_response_item_role.py +5 -0
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_request_target_plan.py +7 -0
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response.py +47 -0
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response_validation_errors_item.py +33 -0
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response_validation_errors_item_resource.py +7 -0
- mirascope/api/_generated/organizations/types/organizations_router_balance_response.py +24 -0
- mirascope/api/_generated/organizations/types/organizations_subscription_response.py +53 -0
- mirascope/api/_generated/organizations/types/organizations_subscription_response_current_plan.py +7 -0
- mirascope/api/_generated/organizations/types/organizations_subscription_response_payment_method.py +26 -0
- mirascope/api/_generated/organizations/types/organizations_subscription_response_scheduled_change.py +34 -0
- mirascope/api/_generated/organizations/types/organizations_subscription_response_scheduled_change_target_plan.py +7 -0
- mirascope/api/_generated/organizations/types/organizations_update_response.py +26 -0
- mirascope/api/_generated/organizations/types/organizations_update_response_role.py +5 -0
- mirascope/api/_generated/organizations/types/organizations_update_subscription_request_target_plan.py +7 -0
- mirascope/api/_generated/organizations/types/organizations_update_subscription_response.py +35 -0
- mirascope/api/_generated/project_memberships/__init__.py +29 -0
- mirascope/api/_generated/project_memberships/client.py +528 -0
- mirascope/api/_generated/project_memberships/raw_client.py +1278 -0
- mirascope/api/_generated/project_memberships/types/__init__.py +33 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_create_request_role.py +7 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_create_response.py +35 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_create_response_role.py +7 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_get_response.py +33 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_get_response_role.py +7 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_list_response_item.py +33 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_list_response_item_role.py +7 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_update_request_role.py +7 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_update_response.py +35 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_update_response_role.py +7 -0
- mirascope/api/_generated/projects/__init__.py +7 -0
- mirascope/api/_generated/projects/client.py +428 -0
- mirascope/api/_generated/projects/raw_client.py +1302 -0
- mirascope/api/_generated/projects/types/__init__.py +10 -0
- mirascope/api/_generated/projects/types/projects_create_response.py +25 -0
- mirascope/api/_generated/projects/types/projects_get_response.py +25 -0
- mirascope/api/_generated/projects/types/projects_list_response_item.py +25 -0
- mirascope/api/_generated/projects/types/projects_update_response.py +25 -0
- mirascope/api/_generated/reference.md +4987 -0
- mirascope/api/_generated/tags/__init__.py +19 -0
- mirascope/api/_generated/tags/client.py +504 -0
- mirascope/api/_generated/tags/raw_client.py +1288 -0
- mirascope/api/_generated/tags/types/__init__.py +17 -0
- mirascope/api/_generated/tags/types/tags_create_response.py +41 -0
- mirascope/api/_generated/tags/types/tags_get_response.py +41 -0
- mirascope/api/_generated/tags/types/tags_list_response.py +23 -0
- mirascope/api/_generated/tags/types/tags_list_response_tags_item.py +41 -0
- mirascope/api/_generated/tags/types/tags_update_response.py +41 -0
- mirascope/api/_generated/token_cost/__init__.py +7 -0
- mirascope/api/_generated/token_cost/client.py +160 -0
- mirascope/api/_generated/token_cost/raw_client.py +264 -0
- mirascope/api/_generated/token_cost/types/__init__.py +8 -0
- mirascope/api/_generated/token_cost/types/token_cost_calculate_request_usage.py +54 -0
- mirascope/api/_generated/token_cost/types/token_cost_calculate_response.py +52 -0
- mirascope/api/_generated/traces/__init__.py +97 -0
- mirascope/api/_generated/traces/client.py +1103 -0
- mirascope/api/_generated/traces/raw_client.py +2322 -0
- mirascope/api/_generated/traces/types/__init__.py +155 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item.py +29 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource.py +27 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item.py +23 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value.py +38 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_array_value.py +19 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_kvlist_value.py +22 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_kvlist_value_values_item.py +20 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item.py +29 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope.py +31 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item.py +23 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value.py +38 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_array_value.py +19 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_kvlist_value.py +22 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_kvlist_value_values_item.py +22 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item.py +48 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item.py +23 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value.py +38 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_array_value.py +19 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_kvlist_value.py +24 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_kvlist_value_values_item.py +22 -0
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_status.py +20 -0
- mirascope/api/_generated/traces/types/traces_create_response.py +24 -0
- mirascope/api/_generated/traces/types/traces_create_response_partial_success.py +22 -0
- mirascope/api/_generated/traces/types/traces_get_analytics_summary_response.py +60 -0
- mirascope/api/_generated/traces/types/traces_get_analytics_summary_response_top_functions_item.py +24 -0
- mirascope/api/_generated/traces/types/traces_get_analytics_summary_response_top_models_item.py +22 -0
- mirascope/api/_generated/traces/types/traces_get_trace_detail_by_env_response.py +33 -0
- mirascope/api/_generated/traces/types/traces_get_trace_detail_by_env_response_spans_item.py +88 -0
- mirascope/api/_generated/traces/types/traces_get_trace_detail_response.py +33 -0
- mirascope/api/_generated/traces/types/traces_get_trace_detail_response_spans_item.py +88 -0
- mirascope/api/_generated/traces/types/traces_list_by_function_hash_response.py +25 -0
- mirascope/api/_generated/traces/types/traces_list_by_function_hash_response_traces_item.py +44 -0
- mirascope/api/_generated/traces/types/traces_search_by_env_request_attribute_filters_item.py +26 -0
- mirascope/api/_generated/traces/types/traces_search_by_env_request_attribute_filters_item_operator.py +7 -0
- mirascope/api/_generated/traces/types/traces_search_by_env_request_sort_by.py +7 -0
- mirascope/api/_generated/traces/types/traces_search_by_env_request_sort_order.py +7 -0
- mirascope/api/_generated/traces/types/traces_search_by_env_response.py +26 -0
- mirascope/api/_generated/traces/types/traces_search_by_env_response_spans_item.py +50 -0
- mirascope/api/_generated/traces/types/traces_search_request_attribute_filters_item.py +26 -0
- mirascope/api/_generated/traces/types/traces_search_request_attribute_filters_item_operator.py +7 -0
- mirascope/api/_generated/traces/types/traces_search_request_sort_by.py +7 -0
- mirascope/api/_generated/traces/types/traces_search_request_sort_order.py +5 -0
- mirascope/api/_generated/traces/types/traces_search_response.py +26 -0
- mirascope/api/_generated/traces/types/traces_search_response_spans_item.py +50 -0
- mirascope/api/_generated/types/__init__.py +85 -0
- mirascope/api/_generated/types/already_exists_error.py +22 -0
- mirascope/api/_generated/types/already_exists_error_tag.py +5 -0
- mirascope/api/_generated/types/bad_request_error_body.py +50 -0
- mirascope/api/_generated/types/click_house_error.py +22 -0
- mirascope/api/_generated/types/database_error.py +22 -0
- mirascope/api/_generated/types/database_error_tag.py +5 -0
- mirascope/api/_generated/types/date.py +3 -0
- mirascope/api/_generated/types/http_api_decode_error.py +27 -0
- mirascope/api/_generated/types/http_api_decode_error_tag.py +5 -0
- mirascope/api/_generated/types/immutable_resource_error.py +22 -0
- mirascope/api/_generated/types/internal_server_error_body.py +49 -0
- mirascope/api/_generated/types/issue.py +38 -0
- mirascope/api/_generated/types/issue_tag.py +10 -0
- mirascope/api/_generated/types/not_found_error_body.py +22 -0
- mirascope/api/_generated/types/not_found_error_tag.py +5 -0
- mirascope/api/_generated/types/number_from_string.py +3 -0
- mirascope/api/_generated/types/permission_denied_error.py +22 -0
- mirascope/api/_generated/types/permission_denied_error_tag.py +5 -0
- mirascope/api/_generated/types/plan_limit_exceeded_error.py +32 -0
- mirascope/api/_generated/types/plan_limit_exceeded_error_tag.py +7 -0
- mirascope/api/_generated/types/pricing_unavailable_error.py +23 -0
- mirascope/api/_generated/types/property_key.py +7 -0
- mirascope/api/_generated/types/property_key_key.py +25 -0
- mirascope/api/_generated/types/property_key_key_tag.py +5 -0
- mirascope/api/_generated/types/rate_limit_error.py +31 -0
- mirascope/api/_generated/types/rate_limit_error_tag.py +5 -0
- mirascope/api/_generated/types/service_unavailable_error_body.py +24 -0
- mirascope/api/_generated/types/service_unavailable_error_tag.py +7 -0
- mirascope/api/_generated/types/stripe_error.py +20 -0
- mirascope/api/_generated/types/subscription_past_due_error.py +31 -0
- mirascope/api/_generated/types/subscription_past_due_error_tag.py +7 -0
- mirascope/api/_generated/types/unauthorized_error_body.py +21 -0
- mirascope/api/_generated/types/unauthorized_error_tag.py +5 -0
- mirascope/api/client.py +255 -0
- mirascope/api/settings.py +99 -0
- mirascope/llm/__init__.py +309 -13
- mirascope/llm/calls/__init__.py +17 -0
- mirascope/llm/calls/calls.py +348 -0
- mirascope/llm/calls/decorator.py +268 -0
- mirascope/llm/content/__init__.py +71 -0
- mirascope/llm/content/audio.py +173 -0
- mirascope/llm/content/document.py +94 -0
- mirascope/llm/content/image.py +206 -0
- mirascope/llm/content/text.py +47 -0
- mirascope/llm/content/thought.py +58 -0
- mirascope/llm/content/tool_call.py +69 -0
- mirascope/llm/content/tool_output.py +43 -0
- mirascope/llm/context/__init__.py +6 -0
- mirascope/llm/context/_utils.py +41 -0
- mirascope/llm/context/context.py +24 -0
- mirascope/llm/exceptions.py +360 -0
- mirascope/llm/formatting/__init__.py +39 -0
- mirascope/llm/formatting/format.py +291 -0
- mirascope/llm/formatting/from_call_args.py +30 -0
- mirascope/llm/formatting/output_parser.py +178 -0
- mirascope/llm/formatting/partial.py +131 -0
- mirascope/llm/formatting/primitives.py +192 -0
- mirascope/llm/formatting/types.py +83 -0
- mirascope/llm/mcp/__init__.py +5 -0
- mirascope/llm/mcp/mcp_client.py +130 -0
- mirascope/llm/messages/__init__.py +35 -0
- mirascope/llm/messages/_utils.py +34 -0
- mirascope/llm/messages/message.py +190 -0
- mirascope/llm/models/__init__.py +21 -0
- mirascope/llm/models/models.py +1339 -0
- mirascope/llm/models/params.py +72 -0
- mirascope/llm/models/thinking_config.py +61 -0
- mirascope/llm/prompts/__init__.py +34 -0
- mirascope/llm/prompts/_utils.py +31 -0
- mirascope/llm/prompts/decorator.py +215 -0
- mirascope/llm/prompts/prompts.py +484 -0
- mirascope/llm/prompts/protocols.py +65 -0
- mirascope/llm/providers/__init__.py +65 -0
- mirascope/llm/providers/anthropic/__init__.py +11 -0
- mirascope/llm/providers/anthropic/_utils/__init__.py +27 -0
- mirascope/llm/providers/anthropic/_utils/beta_decode.py +297 -0
- mirascope/llm/providers/anthropic/_utils/beta_encode.py +272 -0
- mirascope/llm/providers/anthropic/_utils/decode.py +326 -0
- mirascope/llm/providers/anthropic/_utils/encode.py +431 -0
- mirascope/llm/providers/anthropic/_utils/errors.py +46 -0
- mirascope/llm/providers/anthropic/beta_provider.py +338 -0
- mirascope/llm/providers/anthropic/model_id.py +23 -0
- mirascope/llm/providers/anthropic/model_info.py +87 -0
- mirascope/llm/providers/anthropic/provider.py +440 -0
- mirascope/llm/providers/base/__init__.py +14 -0
- mirascope/llm/providers/base/_utils.py +248 -0
- mirascope/llm/providers/base/base_provider.py +1463 -0
- mirascope/llm/providers/base/kwargs.py +12 -0
- mirascope/llm/providers/google/__init__.py +6 -0
- mirascope/llm/providers/google/_utils/__init__.py +17 -0
- mirascope/llm/providers/google/_utils/decode.py +357 -0
- mirascope/llm/providers/google/_utils/encode.py +418 -0
- mirascope/llm/providers/google/_utils/errors.py +50 -0
- mirascope/llm/providers/google/message.py +7 -0
- mirascope/llm/providers/google/model_id.py +22 -0
- mirascope/llm/providers/google/model_info.py +63 -0
- mirascope/llm/providers/google/provider.py +456 -0
- mirascope/llm/providers/mirascope/__init__.py +5 -0
- mirascope/llm/providers/mirascope/_utils.py +73 -0
- mirascope/llm/providers/mirascope/provider.py +313 -0
- mirascope/llm/providers/mlx/__init__.py +9 -0
- mirascope/llm/providers/mlx/_utils.py +141 -0
- mirascope/llm/providers/mlx/encoding/__init__.py +8 -0
- mirascope/llm/providers/mlx/encoding/base.py +69 -0
- mirascope/llm/providers/mlx/encoding/transformers.py +146 -0
- mirascope/llm/providers/mlx/mlx.py +242 -0
- mirascope/llm/providers/mlx/model_id.py +17 -0
- mirascope/llm/providers/mlx/provider.py +416 -0
- mirascope/llm/providers/model_id.py +16 -0
- mirascope/llm/providers/ollama/__init__.py +7 -0
- mirascope/llm/providers/ollama/provider.py +71 -0
- mirascope/llm/providers/openai/__init__.py +15 -0
- mirascope/llm/providers/openai/_utils/__init__.py +5 -0
- mirascope/llm/providers/openai/_utils/errors.py +46 -0
- mirascope/llm/providers/openai/completions/__init__.py +7 -0
- mirascope/llm/providers/openai/completions/_utils/__init__.py +18 -0
- mirascope/llm/providers/openai/completions/_utils/decode.py +252 -0
- mirascope/llm/providers/openai/completions/_utils/encode.py +390 -0
- mirascope/llm/providers/openai/completions/_utils/feature_info.py +50 -0
- mirascope/llm/providers/openai/completions/base_provider.py +522 -0
- mirascope/llm/providers/openai/completions/provider.py +28 -0
- mirascope/llm/providers/openai/model_id.py +31 -0
- mirascope/llm/providers/openai/model_info.py +303 -0
- mirascope/llm/providers/openai/provider.py +405 -0
- mirascope/llm/providers/openai/responses/__init__.py +5 -0
- mirascope/llm/providers/openai/responses/_utils/__init__.py +15 -0
- mirascope/llm/providers/openai/responses/_utils/decode.py +289 -0
- mirascope/llm/providers/openai/responses/_utils/encode.py +399 -0
- mirascope/llm/providers/openai/responses/provider.py +472 -0
- mirascope/llm/providers/openrouter/__init__.py +5 -0
- mirascope/llm/providers/openrouter/provider.py +67 -0
- mirascope/llm/providers/provider_id.py +26 -0
- mirascope/llm/providers/provider_registry.py +305 -0
- mirascope/llm/providers/together/__init__.py +7 -0
- mirascope/llm/providers/together/provider.py +40 -0
- mirascope/llm/responses/__init__.py +66 -0
- mirascope/llm/responses/_utils.py +146 -0
- mirascope/llm/responses/base_response.py +103 -0
- mirascope/llm/responses/base_stream_response.py +824 -0
- mirascope/llm/responses/finish_reason.py +28 -0
- mirascope/llm/responses/response.py +362 -0
- mirascope/llm/responses/root_response.py +248 -0
- mirascope/llm/responses/stream_response.py +577 -0
- mirascope/llm/responses/streams.py +363 -0
- mirascope/llm/responses/usage.py +139 -0
- mirascope/llm/tools/__init__.py +71 -0
- mirascope/llm/tools/_utils.py +34 -0
- mirascope/llm/tools/decorator.py +184 -0
- mirascope/llm/tools/protocols.py +96 -0
- mirascope/llm/tools/provider_tools.py +18 -0
- mirascope/llm/tools/tool_schema.py +321 -0
- mirascope/llm/tools/toolkit.py +178 -0
- mirascope/llm/tools/tools.py +263 -0
- mirascope/llm/tools/types.py +112 -0
- mirascope/llm/tools/web_search_tool.py +32 -0
- mirascope/llm/types/__init__.py +22 -0
- mirascope/llm/types/dataclass.py +9 -0
- mirascope/llm/types/jsonable.py +44 -0
- mirascope/llm/types/type_vars.py +19 -0
- mirascope/ops/__init__.py +129 -0
- mirascope/ops/_internal/__init__.py +5 -0
- mirascope/ops/_internal/closure.py +1172 -0
- mirascope/ops/_internal/configuration.py +177 -0
- mirascope/ops/_internal/context.py +76 -0
- mirascope/ops/_internal/exporters/__init__.py +26 -0
- mirascope/ops/_internal/exporters/exporters.py +362 -0
- mirascope/ops/_internal/exporters/processors.py +104 -0
- mirascope/ops/_internal/exporters/types.py +165 -0
- mirascope/ops/_internal/exporters/utils.py +66 -0
- mirascope/ops/_internal/instrumentation/__init__.py +28 -0
- mirascope/ops/_internal/instrumentation/llm/__init__.py +8 -0
- mirascope/ops/_internal/instrumentation/llm/common.py +500 -0
- mirascope/ops/_internal/instrumentation/llm/cost.py +190 -0
- mirascope/ops/_internal/instrumentation/llm/encode.py +238 -0
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/__init__.py +38 -0
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_input_messages.py +31 -0
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_output_messages.py +38 -0
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_system_instructions.py +18 -0
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/shared.py +100 -0
- mirascope/ops/_internal/instrumentation/llm/llm.py +161 -0
- mirascope/ops/_internal/instrumentation/llm/model.py +1777 -0
- mirascope/ops/_internal/instrumentation/llm/response.py +521 -0
- mirascope/ops/_internal/instrumentation/llm/serialize.py +324 -0
- mirascope/ops/_internal/instrumentation/providers/__init__.py +29 -0
- mirascope/ops/_internal/instrumentation/providers/anthropic.py +78 -0
- mirascope/ops/_internal/instrumentation/providers/base.py +179 -0
- mirascope/ops/_internal/instrumentation/providers/google_genai.py +85 -0
- mirascope/ops/_internal/instrumentation/providers/openai.py +82 -0
- mirascope/ops/_internal/propagation.py +198 -0
- mirascope/ops/_internal/protocols.py +133 -0
- mirascope/ops/_internal/session.py +139 -0
- mirascope/ops/_internal/spans.py +232 -0
- mirascope/ops/_internal/traced_calls.py +389 -0
- mirascope/ops/_internal/traced_functions.py +528 -0
- mirascope/ops/_internal/tracing.py +353 -0
- mirascope/ops/_internal/types.py +13 -0
- mirascope/ops/_internal/utils.py +131 -0
- mirascope/ops/_internal/versioned_calls.py +512 -0
- mirascope/ops/_internal/versioned_functions.py +357 -0
- mirascope/ops/_internal/versioning.py +303 -0
- mirascope/ops/exceptions.py +21 -0
- mirascope-2.1.1.dist-info/METADATA +231 -0
- mirascope-2.1.1.dist-info/RECORD +437 -0
- mirascope-2.1.1.dist-info/WHEEL +4 -0
- mirascope-2.1.1.dist-info/licenses/LICENSE +21 -0
- mirascope/beta/__init__.py +0 -3
- mirascope/beta/openai/__init__.py +0 -17
- mirascope/beta/openai/realtime/__init__.py +0 -13
- mirascope/beta/openai/realtime/_utils/__init__.py +0 -3
- mirascope/beta/openai/realtime/_utils/_audio.py +0 -74
- mirascope/beta/openai/realtime/_utils/_protocols.py +0 -50
- mirascope/beta/openai/realtime/realtime.py +0 -500
- mirascope/beta/openai/realtime/recording.py +0 -98
- mirascope/beta/openai/realtime/tool.py +0 -113
- mirascope/beta/rag/__init__.py +0 -24
- mirascope/beta/rag/base/__init__.py +0 -22
- mirascope/beta/rag/base/chunkers/__init__.py +0 -2
- mirascope/beta/rag/base/chunkers/base_chunker.py +0 -37
- mirascope/beta/rag/base/chunkers/text_chunker.py +0 -33
- mirascope/beta/rag/base/config.py +0 -8
- mirascope/beta/rag/base/document.py +0 -11
- mirascope/beta/rag/base/embedders.py +0 -35
- mirascope/beta/rag/base/embedding_params.py +0 -18
- mirascope/beta/rag/base/embedding_response.py +0 -30
- mirascope/beta/rag/base/query_results.py +0 -7
- mirascope/beta/rag/base/vectorstore_params.py +0 -18
- mirascope/beta/rag/base/vectorstores.py +0 -37
- mirascope/beta/rag/chroma/__init__.py +0 -11
- mirascope/beta/rag/chroma/types.py +0 -57
- mirascope/beta/rag/chroma/vectorstores.py +0 -97
- mirascope/beta/rag/cohere/__init__.py +0 -11
- mirascope/beta/rag/cohere/embedders.py +0 -87
- mirascope/beta/rag/cohere/embedding_params.py +0 -29
- mirascope/beta/rag/cohere/embedding_response.py +0 -29
- mirascope/beta/rag/cohere/py.typed +0 -0
- mirascope/beta/rag/openai/__init__.py +0 -11
- mirascope/beta/rag/openai/embedders.py +0 -144
- mirascope/beta/rag/openai/embedding_params.py +0 -18
- mirascope/beta/rag/openai/embedding_response.py +0 -14
- mirascope/beta/rag/openai/py.typed +0 -0
- mirascope/beta/rag/pinecone/__init__.py +0 -19
- mirascope/beta/rag/pinecone/types.py +0 -143
- mirascope/beta/rag/pinecone/vectorstores.py +0 -148
- mirascope/beta/rag/weaviate/__init__.py +0 -6
- mirascope/beta/rag/weaviate/types.py +0 -92
- mirascope/beta/rag/weaviate/vectorstores.py +0 -103
- mirascope/core/__init__.py +0 -107
- mirascope/core/anthropic/__init__.py +0 -31
- mirascope/core/anthropic/_call.py +0 -67
- mirascope/core/anthropic/_call_kwargs.py +0 -13
- mirascope/core/anthropic/_utils/__init__.py +0 -16
- mirascope/core/anthropic/_utils/_convert_common_call_params.py +0 -25
- mirascope/core/anthropic/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -21
- mirascope/core/anthropic/_utils/_convert_message_params.py +0 -102
- mirascope/core/anthropic/_utils/_get_json_output.py +0 -31
- mirascope/core/anthropic/_utils/_handle_stream.py +0 -113
- mirascope/core/anthropic/_utils/_message_param_converter.py +0 -142
- mirascope/core/anthropic/_utils/_setup_call.py +0 -134
- mirascope/core/anthropic/call_params.py +0 -41
- mirascope/core/anthropic/call_response.py +0 -206
- mirascope/core/anthropic/call_response_chunk.py +0 -132
- mirascope/core/anthropic/dynamic_config.py +0 -40
- mirascope/core/anthropic/py.typed +0 -0
- mirascope/core/anthropic/stream.py +0 -147
- mirascope/core/anthropic/tool.py +0 -101
- mirascope/core/azure/__init__.py +0 -31
- mirascope/core/azure/_call.py +0 -67
- mirascope/core/azure/_call_kwargs.py +0 -13
- mirascope/core/azure/_utils/__init__.py +0 -14
- mirascope/core/azure/_utils/_convert_common_call_params.py +0 -26
- mirascope/core/azure/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -21
- mirascope/core/azure/_utils/_convert_message_params.py +0 -121
- mirascope/core/azure/_utils/_get_credential.py +0 -33
- mirascope/core/azure/_utils/_get_json_output.py +0 -27
- mirascope/core/azure/_utils/_handle_stream.py +0 -130
- mirascope/core/azure/_utils/_message_param_converter.py +0 -117
- mirascope/core/azure/_utils/_setup_call.py +0 -183
- mirascope/core/azure/call_params.py +0 -59
- mirascope/core/azure/call_response.py +0 -215
- mirascope/core/azure/call_response_chunk.py +0 -105
- mirascope/core/azure/dynamic_config.py +0 -30
- mirascope/core/azure/py.typed +0 -0
- mirascope/core/azure/stream.py +0 -147
- mirascope/core/azure/tool.py +0 -93
- mirascope/core/base/__init__.py +0 -84
- mirascope/core/base/_call_factory.py +0 -256
- mirascope/core/base/_create.py +0 -253
- mirascope/core/base/_extract.py +0 -175
- mirascope/core/base/_extract_with_tools.py +0 -189
- mirascope/core/base/_partial.py +0 -95
- mirascope/core/base/_utils/__init__.py +0 -92
- mirascope/core/base/_utils/_base_message_param_converter.py +0 -22
- mirascope/core/base/_utils/_base_type.py +0 -26
- mirascope/core/base/_utils/_convert_base_model_to_base_tool.py +0 -48
- mirascope/core/base/_utils/_convert_base_type_to_base_tool.py +0 -24
- mirascope/core/base/_utils/_convert_function_to_base_tool.py +0 -139
- mirascope/core/base/_utils/_convert_messages_to_message_params.py +0 -171
- mirascope/core/base/_utils/_convert_provider_finish_reason_to_finish_reason.py +0 -20
- mirascope/core/base/_utils/_default_tool_docstring.py +0 -6
- mirascope/core/base/_utils/_extract_tool_return.py +0 -42
- mirascope/core/base/_utils/_fn_is_async.py +0 -15
- mirascope/core/base/_utils/_format_template.py +0 -32
- mirascope/core/base/_utils/_get_audio_type.py +0 -18
- mirascope/core/base/_utils/_get_common_usage.py +0 -20
- mirascope/core/base/_utils/_get_create_fn_or_async_create_fn.py +0 -137
- mirascope/core/base/_utils/_get_document_type.py +0 -7
- mirascope/core/base/_utils/_get_dynamic_configuration.py +0 -69
- mirascope/core/base/_utils/_get_fields_from_call_args.py +0 -34
- mirascope/core/base/_utils/_get_fn_args.py +0 -23
- mirascope/core/base/_utils/_get_image_dimensions.py +0 -39
- mirascope/core/base/_utils/_get_image_type.py +0 -26
- mirascope/core/base/_utils/_get_metadata.py +0 -17
- mirascope/core/base/_utils/_get_possible_user_message_param.py +0 -21
- mirascope/core/base/_utils/_get_prompt_template.py +0 -28
- mirascope/core/base/_utils/_get_template_values.py +0 -51
- mirascope/core/base/_utils/_get_template_variables.py +0 -38
- mirascope/core/base/_utils/_get_unsupported_tool_config_keys.py +0 -10
- mirascope/core/base/_utils/_is_prompt_template.py +0 -24
- mirascope/core/base/_utils/_json_mode_content.py +0 -17
- mirascope/core/base/_utils/_messages_decorator.py +0 -121
- mirascope/core/base/_utils/_parse_content_template.py +0 -321
- mirascope/core/base/_utils/_parse_prompt_messages.py +0 -63
- mirascope/core/base/_utils/_pil_image_to_bytes.py +0 -13
- mirascope/core/base/_utils/_protocols.py +0 -901
- mirascope/core/base/_utils/_setup_call.py +0 -79
- mirascope/core/base/_utils/_setup_extract_tool.py +0 -30
- mirascope/core/base/call_kwargs.py +0 -13
- mirascope/core/base/call_params.py +0 -36
- mirascope/core/base/call_response.py +0 -340
- mirascope/core/base/call_response_chunk.py +0 -130
- mirascope/core/base/dynamic_config.py +0 -82
- mirascope/core/base/from_call_args.py +0 -30
- mirascope/core/base/merge_decorators.py +0 -59
- mirascope/core/base/message_param.py +0 -162
- mirascope/core/base/messages.py +0 -111
- mirascope/core/base/metadata.py +0 -13
- mirascope/core/base/prompt.py +0 -497
- mirascope/core/base/response_model_config_dict.py +0 -9
- mirascope/core/base/stream.py +0 -479
- mirascope/core/base/stream_config.py +0 -11
- mirascope/core/base/structured_stream.py +0 -296
- mirascope/core/base/tool.py +0 -205
- mirascope/core/base/toolkit.py +0 -176
- mirascope/core/base/types.py +0 -344
- mirascope/core/bedrock/__init__.py +0 -34
- mirascope/core/bedrock/_call.py +0 -68
- mirascope/core/bedrock/_call_kwargs.py +0 -12
- mirascope/core/bedrock/_types.py +0 -104
- mirascope/core/bedrock/_utils/__init__.py +0 -14
- mirascope/core/bedrock/_utils/_convert_common_call_params.py +0 -39
- mirascope/core/bedrock/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -23
- mirascope/core/bedrock/_utils/_convert_message_params.py +0 -111
- mirascope/core/bedrock/_utils/_get_json_output.py +0 -30
- mirascope/core/bedrock/_utils/_handle_stream.py +0 -104
- mirascope/core/bedrock/_utils/_message_param_converter.py +0 -171
- mirascope/core/bedrock/_utils/_setup_call.py +0 -258
- mirascope/core/bedrock/call_params.py +0 -38
- mirascope/core/bedrock/call_response.py +0 -249
- mirascope/core/bedrock/call_response_chunk.py +0 -111
- mirascope/core/bedrock/dynamic_config.py +0 -37
- mirascope/core/bedrock/py.typed +0 -0
- mirascope/core/bedrock/stream.py +0 -154
- mirascope/core/bedrock/tool.py +0 -96
- mirascope/core/cohere/__init__.py +0 -30
- mirascope/core/cohere/_call.py +0 -67
- mirascope/core/cohere/_call_kwargs.py +0 -11
- mirascope/core/cohere/_types.py +0 -20
- mirascope/core/cohere/_utils/__init__.py +0 -14
- mirascope/core/cohere/_utils/_convert_common_call_params.py +0 -26
- mirascope/core/cohere/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -24
- mirascope/core/cohere/_utils/_convert_message_params.py +0 -32
- mirascope/core/cohere/_utils/_get_json_output.py +0 -30
- mirascope/core/cohere/_utils/_handle_stream.py +0 -35
- mirascope/core/cohere/_utils/_message_param_converter.py +0 -54
- mirascope/core/cohere/_utils/_setup_call.py +0 -150
- mirascope/core/cohere/call_params.py +0 -62
- mirascope/core/cohere/call_response.py +0 -205
- mirascope/core/cohere/call_response_chunk.py +0 -125
- mirascope/core/cohere/dynamic_config.py +0 -32
- mirascope/core/cohere/py.typed +0 -0
- mirascope/core/cohere/stream.py +0 -113
- mirascope/core/cohere/tool.py +0 -93
- mirascope/core/costs/__init__.py +0 -5
- mirascope/core/costs/_anthropic_calculate_cost.py +0 -219
- mirascope/core/costs/_azure_calculate_cost.py +0 -11
- mirascope/core/costs/_bedrock_calculate_cost.py +0 -15
- mirascope/core/costs/_cohere_calculate_cost.py +0 -44
- mirascope/core/costs/_gemini_calculate_cost.py +0 -67
- mirascope/core/costs/_google_calculate_cost.py +0 -427
- mirascope/core/costs/_groq_calculate_cost.py +0 -156
- mirascope/core/costs/_litellm_calculate_cost.py +0 -11
- mirascope/core/costs/_mistral_calculate_cost.py +0 -64
- mirascope/core/costs/_openai_calculate_cost.py +0 -416
- mirascope/core/costs/_vertex_calculate_cost.py +0 -67
- mirascope/core/costs/_xai_calculate_cost.py +0 -104
- mirascope/core/costs/calculate_cost.py +0 -86
- mirascope/core/gemini/__init__.py +0 -40
- mirascope/core/gemini/_call.py +0 -67
- mirascope/core/gemini/_call_kwargs.py +0 -12
- mirascope/core/gemini/_utils/__init__.py +0 -14
- mirascope/core/gemini/_utils/_convert_common_call_params.py +0 -39
- mirascope/core/gemini/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -23
- mirascope/core/gemini/_utils/_convert_message_params.py +0 -156
- mirascope/core/gemini/_utils/_get_json_output.py +0 -35
- mirascope/core/gemini/_utils/_handle_stream.py +0 -33
- mirascope/core/gemini/_utils/_message_param_converter.py +0 -209
- mirascope/core/gemini/_utils/_setup_call.py +0 -149
- mirascope/core/gemini/call_params.py +0 -52
- mirascope/core/gemini/call_response.py +0 -216
- mirascope/core/gemini/call_response_chunk.py +0 -100
- mirascope/core/gemini/dynamic_config.py +0 -26
- mirascope/core/gemini/stream.py +0 -120
- mirascope/core/gemini/tool.py +0 -104
- mirascope/core/google/__init__.py +0 -29
- mirascope/core/google/_call.py +0 -67
- mirascope/core/google/_call_kwargs.py +0 -13
- mirascope/core/google/_utils/__init__.py +0 -14
- mirascope/core/google/_utils/_convert_common_call_params.py +0 -38
- mirascope/core/google/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -27
- mirascope/core/google/_utils/_convert_message_params.py +0 -206
- mirascope/core/google/_utils/_get_json_output.py +0 -37
- mirascope/core/google/_utils/_handle_stream.py +0 -35
- mirascope/core/google/_utils/_message_param_converter.py +0 -162
- mirascope/core/google/_utils/_setup_call.py +0 -201
- mirascope/core/google/_utils/_validate_media_type.py +0 -34
- mirascope/core/google/call_params.py +0 -22
- mirascope/core/google/call_response.py +0 -232
- mirascope/core/google/call_response_chunk.py +0 -110
- mirascope/core/google/dynamic_config.py +0 -26
- mirascope/core/google/stream.py +0 -143
- mirascope/core/google/tool.py +0 -146
- mirascope/core/groq/__init__.py +0 -30
- mirascope/core/groq/_call.py +0 -67
- mirascope/core/groq/_call_kwargs.py +0 -13
- mirascope/core/groq/_utils/__init__.py +0 -14
- mirascope/core/groq/_utils/_convert_common_call_params.py +0 -26
- mirascope/core/groq/_utils/_convert_message_params.py +0 -112
- mirascope/core/groq/_utils/_get_json_output.py +0 -27
- mirascope/core/groq/_utils/_handle_stream.py +0 -123
- mirascope/core/groq/_utils/_message_param_converter.py +0 -89
- mirascope/core/groq/_utils/_setup_call.py +0 -132
- mirascope/core/groq/call_params.py +0 -52
- mirascope/core/groq/call_response.py +0 -213
- mirascope/core/groq/call_response_chunk.py +0 -104
- mirascope/core/groq/dynamic_config.py +0 -29
- mirascope/core/groq/py.typed +0 -0
- mirascope/core/groq/stream.py +0 -135
- mirascope/core/groq/tool.py +0 -80
- mirascope/core/litellm/__init__.py +0 -28
- mirascope/core/litellm/_call.py +0 -67
- mirascope/core/litellm/_utils/__init__.py +0 -5
- mirascope/core/litellm/_utils/_setup_call.py +0 -109
- mirascope/core/litellm/call_params.py +0 -10
- mirascope/core/litellm/call_response.py +0 -24
- mirascope/core/litellm/call_response_chunk.py +0 -14
- mirascope/core/litellm/dynamic_config.py +0 -8
- mirascope/core/litellm/py.typed +0 -0
- mirascope/core/litellm/stream.py +0 -86
- mirascope/core/litellm/tool.py +0 -13
- mirascope/core/mistral/__init__.py +0 -36
- mirascope/core/mistral/_call.py +0 -65
- mirascope/core/mistral/_call_kwargs.py +0 -19
- mirascope/core/mistral/_utils/__init__.py +0 -14
- mirascope/core/mistral/_utils/_convert_common_call_params.py +0 -24
- mirascope/core/mistral/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -22
- mirascope/core/mistral/_utils/_convert_message_params.py +0 -122
- mirascope/core/mistral/_utils/_get_json_output.py +0 -34
- mirascope/core/mistral/_utils/_handle_stream.py +0 -139
- mirascope/core/mistral/_utils/_message_param_converter.py +0 -176
- mirascope/core/mistral/_utils/_setup_call.py +0 -154
- mirascope/core/mistral/call_params.py +0 -36
- mirascope/core/mistral/call_response.py +0 -205
- mirascope/core/mistral/call_response_chunk.py +0 -105
- mirascope/core/mistral/dynamic_config.py +0 -33
- mirascope/core/mistral/py.typed +0 -0
- mirascope/core/mistral/stream.py +0 -120
- mirascope/core/mistral/tool.py +0 -80
- mirascope/core/openai/__init__.py +0 -31
- mirascope/core/openai/_call.py +0 -67
- mirascope/core/openai/_call_kwargs.py +0 -13
- mirascope/core/openai/_utils/__init__.py +0 -14
- mirascope/core/openai/_utils/_convert_common_call_params.py +0 -26
- mirascope/core/openai/_utils/_convert_message_params.py +0 -146
- mirascope/core/openai/_utils/_get_json_output.py +0 -31
- mirascope/core/openai/_utils/_handle_stream.py +0 -138
- mirascope/core/openai/_utils/_message_param_converter.py +0 -105
- mirascope/core/openai/_utils/_setup_call.py +0 -155
- mirascope/core/openai/call_params.py +0 -91
- mirascope/core/openai/call_response.py +0 -273
- mirascope/core/openai/call_response_chunk.py +0 -139
- mirascope/core/openai/dynamic_config.py +0 -34
- mirascope/core/openai/py.typed +0 -0
- mirascope/core/openai/stream.py +0 -185
- mirascope/core/openai/tool.py +0 -101
- mirascope/core/py.typed +0 -0
- mirascope/core/vertex/__init__.py +0 -45
- mirascope/core/vertex/_call.py +0 -62
- mirascope/core/vertex/_call_kwargs.py +0 -12
- mirascope/core/vertex/_utils/__init__.py +0 -14
- mirascope/core/vertex/_utils/_convert_common_call_params.py +0 -37
- mirascope/core/vertex/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -23
- mirascope/core/vertex/_utils/_convert_message_params.py +0 -171
- mirascope/core/vertex/_utils/_get_json_output.py +0 -36
- mirascope/core/vertex/_utils/_handle_stream.py +0 -33
- mirascope/core/vertex/_utils/_message_param_converter.py +0 -133
- mirascope/core/vertex/_utils/_setup_call.py +0 -160
- mirascope/core/vertex/call_params.py +0 -24
- mirascope/core/vertex/call_response.py +0 -206
- mirascope/core/vertex/call_response_chunk.py +0 -99
- mirascope/core/vertex/dynamic_config.py +0 -28
- mirascope/core/vertex/stream.py +0 -119
- mirascope/core/vertex/tool.py +0 -101
- mirascope/core/xai/__init__.py +0 -28
- mirascope/core/xai/_call.py +0 -67
- mirascope/core/xai/_utils/__init__.py +0 -5
- mirascope/core/xai/_utils/_setup_call.py +0 -113
- mirascope/core/xai/call_params.py +0 -10
- mirascope/core/xai/call_response.py +0 -16
- mirascope/core/xai/call_response_chunk.py +0 -14
- mirascope/core/xai/dynamic_config.py +0 -8
- mirascope/core/xai/py.typed +0 -0
- mirascope/core/xai/stream.py +0 -57
- mirascope/core/xai/tool.py +0 -13
- mirascope/experimental/graphs/__init__.py +0 -5
- mirascope/experimental/graphs/finite_state_machine.py +0 -714
- mirascope/integrations/__init__.py +0 -16
- mirascope/integrations/_middleware_factory.py +0 -403
- mirascope/integrations/langfuse/__init__.py +0 -3
- mirascope/integrations/langfuse/_utils.py +0 -114
- mirascope/integrations/langfuse/_with_langfuse.py +0 -70
- mirascope/integrations/logfire/__init__.py +0 -3
- mirascope/integrations/logfire/_utils.py +0 -225
- mirascope/integrations/logfire/_with_logfire.py +0 -63
- mirascope/integrations/otel/__init__.py +0 -10
- mirascope/integrations/otel/_utils.py +0 -270
- mirascope/integrations/otel/_with_hyperdx.py +0 -60
- mirascope/integrations/otel/_with_otel.py +0 -59
- mirascope/integrations/tenacity.py +0 -14
- mirascope/llm/_call.py +0 -401
- mirascope/llm/_context.py +0 -384
- mirascope/llm/_override.py +0 -3639
- mirascope/llm/_protocols.py +0 -500
- mirascope/llm/_response_metaclass.py +0 -31
- mirascope/llm/call_response.py +0 -167
- mirascope/llm/call_response_chunk.py +0 -66
- mirascope/llm/stream.py +0 -162
- mirascope/llm/tool.py +0 -64
- mirascope/mcp/__init__.py +0 -7
- mirascope/mcp/_utils.py +0 -277
- mirascope/mcp/client.py +0 -167
- mirascope/mcp/server.py +0 -356
- mirascope/mcp/tools.py +0 -110
- mirascope/py.typed +0 -0
- mirascope/retries/__init__.py +0 -11
- mirascope/retries/fallback.py +0 -128
- mirascope/retries/tenacity.py +0 -50
- mirascope/tools/__init__.py +0 -37
- mirascope/tools/base.py +0 -98
- mirascope/tools/system/__init__.py +0 -0
- mirascope/tools/system/_docker_operation.py +0 -166
- mirascope/tools/system/_file_system.py +0 -267
- mirascope/tools/web/__init__.py +0 -0
- mirascope/tools/web/_duckduckgo.py +0 -111
- mirascope/tools/web/_httpx.py +0 -125
- mirascope/tools/web/_parse_url_content.py +0 -94
- mirascope/tools/web/_requests.py +0 -54
- mirascope/v0/__init__.py +0 -43
- mirascope/v0/anthropic.py +0 -54
- mirascope/v0/base/__init__.py +0 -12
- mirascope/v0/base/calls.py +0 -118
- mirascope/v0/base/extractors.py +0 -122
- mirascope/v0/base/ops_utils.py +0 -207
- mirascope/v0/base/prompts.py +0 -48
- mirascope/v0/base/types.py +0 -14
- mirascope/v0/base/utils.py +0 -21
- mirascope/v0/openai.py +0 -54
- mirascope-1.22.4.dist-info/METADATA +0 -169
- mirascope-1.22.4.dist-info/RECORD +0 -377
- mirascope-1.22.4.dist-info/WHEEL +0 -4
- mirascope-1.22.4.dist-info/licenses/LICENSE +0 -21
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
"""Base class for StreamResponse and AsyncStreamResponse."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterator, Iterator, Sequence
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Generic, Literal, TypeAlias, TypeVar
|
|
6
|
+
|
|
7
|
+
from ..content import (
|
|
8
|
+
AssistantContentChunk,
|
|
9
|
+
AssistantContentPart,
|
|
10
|
+
Text,
|
|
11
|
+
TextChunk,
|
|
12
|
+
TextEndChunk,
|
|
13
|
+
TextStartChunk,
|
|
14
|
+
Thought,
|
|
15
|
+
ThoughtChunk,
|
|
16
|
+
ThoughtEndChunk,
|
|
17
|
+
ThoughtStartChunk,
|
|
18
|
+
ToolCall,
|
|
19
|
+
ToolCallChunk,
|
|
20
|
+
ToolCallEndChunk,
|
|
21
|
+
ToolCallStartChunk,
|
|
22
|
+
)
|
|
23
|
+
from ..formatting import (
|
|
24
|
+
Format,
|
|
25
|
+
FormattableT,
|
|
26
|
+
Partial,
|
|
27
|
+
is_output_parser,
|
|
28
|
+
)
|
|
29
|
+
from ..messages import AssistantMessage, Message
|
|
30
|
+
from ..tools import FORMAT_TOOL_NAME, ToolkitT
|
|
31
|
+
from ..types import Jsonable
|
|
32
|
+
from .finish_reason import FinishReasonChunk
|
|
33
|
+
from .root_response import RootResponse
|
|
34
|
+
from .streams import (
|
|
35
|
+
AsyncStream,
|
|
36
|
+
AsyncTextStream,
|
|
37
|
+
AsyncThoughtStream,
|
|
38
|
+
AsyncToolCallStream,
|
|
39
|
+
Stream,
|
|
40
|
+
TextStream,
|
|
41
|
+
ThoughtStream,
|
|
42
|
+
ToolCallStream,
|
|
43
|
+
)
|
|
44
|
+
from .usage import Usage, UsageDeltaChunk
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from ..models import Params
|
|
48
|
+
from ..providers import ModelId, ProviderId
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
StreamResponseT = TypeVar("StreamResponseT", bound="BaseStreamResponse[Any, Any, Any]")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(kw_only=True)
|
|
55
|
+
class RawStreamEventChunk:
|
|
56
|
+
"""A chunk containing a raw stream event from the underlying provider.
|
|
57
|
+
|
|
58
|
+
Will be accumulated on `StreamResponse.raw` for debugging purposes.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
type: Literal["raw_stream_event_chunk"] = "raw_stream_event_chunk"
|
|
62
|
+
|
|
63
|
+
raw_stream_event: Any
|
|
64
|
+
"""The raw stream event from the underlying provider."""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(kw_only=True)
|
|
68
|
+
class RawMessageChunk:
|
|
69
|
+
"""A chunk containing provider-specific raw message content that will be added to the `AssistantMessage`.
|
|
70
|
+
|
|
71
|
+
This chunk contains a provider-specific representation of a piece of content that
|
|
72
|
+
will be added to the `AssistantMessage` reconstructed by the containing stream.
|
|
73
|
+
This content should be a Jsonable Python object for serialization purposes.
|
|
74
|
+
|
|
75
|
+
The intention is that this content may be passed as-is back to the provider when the
|
|
76
|
+
generated `AssistantMessage` is being reused in conversation.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
type: Literal["raw_message_chunk"] = "raw_message_chunk"
|
|
80
|
+
|
|
81
|
+
raw_message: Jsonable
|
|
82
|
+
"""The provider-specific raw content.
|
|
83
|
+
|
|
84
|
+
Should be a Jsonable object.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
StreamResponseChunk: TypeAlias = (
|
|
89
|
+
AssistantContentChunk
|
|
90
|
+
| FinishReasonChunk
|
|
91
|
+
| RawStreamEventChunk
|
|
92
|
+
| RawMessageChunk
|
|
93
|
+
| UsageDeltaChunk
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
ChunkIterator: TypeAlias = Iterator[StreamResponseChunk]
|
|
97
|
+
"""Synchronous iterator yielding chunks with raw data."""
|
|
98
|
+
|
|
99
|
+
AsyncChunkIterator: TypeAlias = AsyncIterator[StreamResponseChunk]
|
|
100
|
+
"""Asynchronous iterator yielding chunks with raw data."""
|
|
101
|
+
|
|
102
|
+
ChunkIteratorT = TypeVar("ChunkIteratorT", bound=ChunkIterator | AsyncChunkIterator)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class BaseStreamResponse(
|
|
106
|
+
RootResponse[ToolkitT, FormattableT],
|
|
107
|
+
Generic[ChunkIteratorT, ToolkitT, FormattableT],
|
|
108
|
+
):
|
|
109
|
+
"""Base class underpinning StreamResponse and AsyncStreamResponse.
|
|
110
|
+
|
|
111
|
+
Manages chunk handling logic for both.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
raw_stream_events: Sequence[Any]
|
|
115
|
+
"""The raw stream event chunks from the LLM. Provider-specific."""
|
|
116
|
+
|
|
117
|
+
chunks: Sequence[AssistantContentChunk]
|
|
118
|
+
"""All of the Mirascope chunks consumed from the stream."""
|
|
119
|
+
|
|
120
|
+
content: Sequence[AssistantContentPart]
|
|
121
|
+
"""The content generated by the LLM.
|
|
122
|
+
|
|
123
|
+
Content is updated in this array as it is consumed by the stream. Text content will
|
|
124
|
+
update with each text chunk (this will mutate the Text object that is returned
|
|
125
|
+
rather than creating a new one). Other content will be added once each part
|
|
126
|
+
is fully streamed.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
messages: list[Message]
|
|
130
|
+
"""The message history, including the most recent assistant message.
|
|
131
|
+
|
|
132
|
+
The most recent assistant message will have all of the completed content that has
|
|
133
|
+
already been consumed from the stream. Text content will be included as each chunk
|
|
134
|
+
is processed; other content will be included only when its corresponding part is
|
|
135
|
+
completed (to avoid partial tool calls and the like). If no content has been
|
|
136
|
+
streamed, then the final assistant message will be present (to maintain turn order
|
|
137
|
+
expectations), but will be empty.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
texts: Sequence[Text]
|
|
141
|
+
"""The text content in the generated response, if any.
|
|
142
|
+
|
|
143
|
+
Text content updates with each text chunk as it streams. The `Text` objects are
|
|
144
|
+
mutated in place rather than creating new ones for each chunk.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
tool_calls: Sequence[ToolCall]
|
|
148
|
+
"""The tools the LLM wants called on its behalf, if any.
|
|
149
|
+
|
|
150
|
+
Tool calls are only added to this sequence once they have been fully streamed
|
|
151
|
+
to avoid partial tool calls in the response.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
thoughts: Sequence[Thought]
|
|
155
|
+
"""The readable thoughts from the model's thinking process, if any.
|
|
156
|
+
|
|
157
|
+
The thoughts may be direct output from the model thinking process, or may be a
|
|
158
|
+
generated summary. (This depends on the provider; newer models tend to summarize.)
|
|
159
|
+
|
|
160
|
+
Thoughts are added to the sequence as they are streamed. The `Thought` objects are
|
|
161
|
+
mutated in place rather than creating new ones for each chunk.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
consumed: bool = False
|
|
165
|
+
"""Whether the stream has been fully consumed.
|
|
166
|
+
|
|
167
|
+
This is True after all chunks have been processed from the underlying iterator.
|
|
168
|
+
When False, more content may be available by calling the stream methods.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def __init__(
|
|
172
|
+
self,
|
|
173
|
+
*,
|
|
174
|
+
provider_id: "ProviderId",
|
|
175
|
+
model_id: "ModelId",
|
|
176
|
+
provider_model_name: str,
|
|
177
|
+
params: "Params",
|
|
178
|
+
toolkit: ToolkitT,
|
|
179
|
+
format: Format[FormattableT] | None = None,
|
|
180
|
+
input_messages: Sequence[Message],
|
|
181
|
+
chunk_iterator: ChunkIteratorT,
|
|
182
|
+
usage: Usage | None = None,
|
|
183
|
+
) -> None:
|
|
184
|
+
"""Initialize the BaseStreamResponse.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
provider: The provider name (e.g. "anthropic", "openai").
|
|
188
|
+
model_id: The model identifier that generated the response.
|
|
189
|
+
provider_model_name: Optional provider-specific model name. May include
|
|
190
|
+
provider-specific additional info (like api mode in "gpt-5:responses").
|
|
191
|
+
params: The params used to generate the response (or None).
|
|
192
|
+
toolkit: Toolkit containing all the tools used to generate the response.
|
|
193
|
+
format: The `Format` for the expected structured output format (or None).
|
|
194
|
+
input_messages: The input messages that were sent to the LLM
|
|
195
|
+
usage: Token usage statistics for the response.
|
|
196
|
+
|
|
197
|
+
The BaseStreamResponse will process the tuples to build the chunks and raw lists
|
|
198
|
+
as the stream is consumed.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
self.provider_id = provider_id
|
|
202
|
+
self.model_id = model_id
|
|
203
|
+
self.provider_model_name = provider_model_name
|
|
204
|
+
self.params = params
|
|
205
|
+
self.toolkit = toolkit
|
|
206
|
+
self.usage = usage
|
|
207
|
+
self.format = format
|
|
208
|
+
|
|
209
|
+
# Internal-only lists which we mutate (append) during chunk processing
|
|
210
|
+
self._chunks: list[AssistantContentChunk] = []
|
|
211
|
+
self._content: list[AssistantContentPart] = []
|
|
212
|
+
self._texts: list[Text] = []
|
|
213
|
+
self._thoughts: list[Thought] = []
|
|
214
|
+
self._tool_calls: list[ToolCall] = []
|
|
215
|
+
self._raw_stream_events: list[Any] = []
|
|
216
|
+
self._last_raw_stream_event_chunk: Any | None = None
|
|
217
|
+
|
|
218
|
+
# Externally-facing references typed as immutable Sequences
|
|
219
|
+
self.chunks = self._chunks
|
|
220
|
+
self.content = self._content
|
|
221
|
+
self.texts = self._texts
|
|
222
|
+
self.thoughts = self._thoughts
|
|
223
|
+
self.tool_calls = self._tool_calls
|
|
224
|
+
self.raw_stream_events = self._raw_stream_events
|
|
225
|
+
|
|
226
|
+
self.finish_reason = None
|
|
227
|
+
|
|
228
|
+
self._assistant_message = AssistantMessage(
|
|
229
|
+
content=self._content,
|
|
230
|
+
provider_id=provider_id,
|
|
231
|
+
model_id=model_id,
|
|
232
|
+
provider_model_name=provider_model_name,
|
|
233
|
+
raw_message=None,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
self.messages = list(input_messages) + [self._assistant_message]
|
|
237
|
+
|
|
238
|
+
self._chunk_iterator = chunk_iterator
|
|
239
|
+
self._current_content: Text | Thought | None = None
|
|
240
|
+
self._current_tool_calls: dict[str, ToolCall] = {}
|
|
241
|
+
|
|
242
|
+
self._processing_format_tool: bool = False
|
|
243
|
+
|
|
244
|
+
def _transform_format_tool_chunks(
|
|
245
|
+
self, chunk: AssistantContentChunk
|
|
246
|
+
) -> AssistantContentChunk:
|
|
247
|
+
if chunk.type == "tool_call_start_chunk" and chunk.name.startswith(
|
|
248
|
+
FORMAT_TOOL_NAME
|
|
249
|
+
):
|
|
250
|
+
self._processing_format_tool = True
|
|
251
|
+
return TextStartChunk()
|
|
252
|
+
if self._processing_format_tool and chunk.type == "tool_call_chunk":
|
|
253
|
+
return TextChunk(delta=chunk.delta)
|
|
254
|
+
if self._processing_format_tool and chunk.type == "tool_call_end_chunk":
|
|
255
|
+
self._processing_format_tool = False
|
|
256
|
+
return TextEndChunk()
|
|
257
|
+
return chunk
|
|
258
|
+
|
|
259
|
+
def _handle_chunk(self, chunk: AssistantContentChunk) -> AssistantContentChunk:
|
|
260
|
+
if self.finish_reason:
|
|
261
|
+
raise RuntimeError(
|
|
262
|
+
f"Stream already finished with reason: {self.finish_reason}"
|
|
263
|
+
)
|
|
264
|
+
chunk = self._transform_format_tool_chunks(chunk)
|
|
265
|
+
|
|
266
|
+
if chunk.content_type == "text":
|
|
267
|
+
self._handle_text_chunk(chunk)
|
|
268
|
+
elif chunk.content_type == "tool_call":
|
|
269
|
+
self._handle_tool_call_chunk(chunk)
|
|
270
|
+
elif chunk.content_type == "thought":
|
|
271
|
+
self._handle_thought_chunk(chunk)
|
|
272
|
+
else:
|
|
273
|
+
raise NotImplementedError
|
|
274
|
+
|
|
275
|
+
self._chunks.append(chunk)
|
|
276
|
+
return chunk
|
|
277
|
+
|
|
278
|
+
def _handle_text_chunk(
|
|
279
|
+
self, chunk: TextStartChunk | TextChunk | TextEndChunk
|
|
280
|
+
) -> None:
|
|
281
|
+
if chunk.type == "text_start_chunk":
|
|
282
|
+
if self._current_content or self._current_tool_calls:
|
|
283
|
+
raise RuntimeError(
|
|
284
|
+
"Received text_start_chunk while processing another chunk"
|
|
285
|
+
)
|
|
286
|
+
self._current_content = Text(text="")
|
|
287
|
+
# Text gets included in content even when unfinished.
|
|
288
|
+
self._content.append(self._current_content)
|
|
289
|
+
self._texts.append(self._current_content)
|
|
290
|
+
|
|
291
|
+
elif chunk.type == "text_chunk":
|
|
292
|
+
if self._current_content is None or self._current_content.type != "text":
|
|
293
|
+
raise RuntimeError("Received text_chunk while not processing text.")
|
|
294
|
+
self._current_content.text += chunk.delta
|
|
295
|
+
|
|
296
|
+
elif chunk.type == "text_end_chunk":
|
|
297
|
+
if self._current_content is None or self._current_content.type != "text":
|
|
298
|
+
raise RuntimeError("Received text_end_chunk while not processing text.")
|
|
299
|
+
self._current_content = None
|
|
300
|
+
|
|
301
|
+
def _handle_thought_chunk(
|
|
302
|
+
self, chunk: ThoughtStartChunk | ThoughtChunk | ThoughtEndChunk
|
|
303
|
+
) -> None:
|
|
304
|
+
if chunk.type == "thought_start_chunk":
|
|
305
|
+
if self._current_content or self._current_tool_calls:
|
|
306
|
+
raise RuntimeError(
|
|
307
|
+
"Received thought_start_chunk while processing another chunk"
|
|
308
|
+
)
|
|
309
|
+
self._current_content = Thought(thought="")
|
|
310
|
+
# Thoughts get included even when unfinished.
|
|
311
|
+
self._content.append(self._current_content)
|
|
312
|
+
self._thoughts.append(self._current_content)
|
|
313
|
+
|
|
314
|
+
elif chunk.type == "thought_chunk":
|
|
315
|
+
if self._current_content is None or self._current_content.type != "thought":
|
|
316
|
+
raise RuntimeError(
|
|
317
|
+
"Received thought_chunk while not processing thought."
|
|
318
|
+
)
|
|
319
|
+
self._current_content.thought += chunk.delta
|
|
320
|
+
|
|
321
|
+
elif chunk.type == "thought_end_chunk":
|
|
322
|
+
if self._current_content is None or self._current_content.type != "thought":
|
|
323
|
+
raise RuntimeError(
|
|
324
|
+
"Received thought_end_chunk while not processing thought."
|
|
325
|
+
)
|
|
326
|
+
self._current_content = None
|
|
327
|
+
|
|
328
|
+
def _handle_tool_call_chunk(
|
|
329
|
+
self, chunk: ToolCallStartChunk | ToolCallChunk | ToolCallEndChunk
|
|
330
|
+
) -> None:
|
|
331
|
+
if chunk.type == "tool_call_start_chunk":
|
|
332
|
+
if self._current_content:
|
|
333
|
+
raise RuntimeError(
|
|
334
|
+
"Received tool_call_start_chunk while processing another chunk"
|
|
335
|
+
)
|
|
336
|
+
if chunk.id in self._current_tool_calls:
|
|
337
|
+
raise RuntimeError("Got tool_call_start_chunk with conflicting id")
|
|
338
|
+
# Create a new tool call and track it by ID
|
|
339
|
+
# Multiple tool calls can be in progress simultaneously (interleaved)
|
|
340
|
+
tool_call = ToolCall(
|
|
341
|
+
id=chunk.id,
|
|
342
|
+
name=chunk.name,
|
|
343
|
+
args="",
|
|
344
|
+
)
|
|
345
|
+
self._current_tool_calls[chunk.id] = tool_call
|
|
346
|
+
|
|
347
|
+
elif chunk.type == "tool_call_chunk":
|
|
348
|
+
# Look up the tool call by ID
|
|
349
|
+
tool_call = self._current_tool_calls.get(chunk.id)
|
|
350
|
+
if tool_call is None:
|
|
351
|
+
raise RuntimeError(
|
|
352
|
+
f"Received tool_call_chunk for unknown tool call ID: {chunk.id}"
|
|
353
|
+
)
|
|
354
|
+
tool_call.args += chunk.delta
|
|
355
|
+
|
|
356
|
+
elif chunk.type == "tool_call_end_chunk":
|
|
357
|
+
# Finalize the tool call
|
|
358
|
+
tool_call = self._current_tool_calls.get(chunk.id)
|
|
359
|
+
if tool_call is None:
|
|
360
|
+
raise RuntimeError(
|
|
361
|
+
f"Received tool_call_end_chunk for unknown tool call ID: {chunk.id}"
|
|
362
|
+
)
|
|
363
|
+
if not tool_call.args:
|
|
364
|
+
tool_call.args = "{}"
|
|
365
|
+
self._content.append(tool_call)
|
|
366
|
+
self._tool_calls.append(tool_call)
|
|
367
|
+
del self._current_tool_calls[chunk.id]
|
|
368
|
+
|
|
369
|
+
def _pretty_chunk(self, chunk: AssistantContentChunk, spacer: str) -> str:
|
|
370
|
+
match chunk.type:
|
|
371
|
+
case "text_start_chunk":
|
|
372
|
+
return spacer
|
|
373
|
+
case "text_chunk":
|
|
374
|
+
return chunk.delta
|
|
375
|
+
case "tool_call_start_chunk":
|
|
376
|
+
return spacer + f"**ToolCall ({chunk.name}):** "
|
|
377
|
+
case "tool_call_chunk":
|
|
378
|
+
return chunk.delta
|
|
379
|
+
case "thought_start_chunk":
|
|
380
|
+
return spacer + "**Thinking:**\n "
|
|
381
|
+
case "thought_chunk":
|
|
382
|
+
return chunk.delta.replace("\n", "\n ") # Indent every line
|
|
383
|
+
case _:
|
|
384
|
+
return ""
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
class BaseSyncStreamResponse(BaseStreamResponse[ChunkIterator, ToolkitT, FormattableT]):
|
|
388
|
+
"""A base class for synchronous Stream Responses."""
|
|
389
|
+
|
|
390
|
+
def streams(self) -> Iterator[Stream]:
|
|
391
|
+
"""Returns an iterator that yields streams for each content part in the response.
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
Iterator[Stream]: Synchronous iterator yielding Stream objects
|
|
395
|
+
|
|
396
|
+
Each content part in the response will correspond to one stream, which will yield
|
|
397
|
+
chunks of content as they come in from the underlying LLM.
|
|
398
|
+
|
|
399
|
+
Fully iterating through this iterator will fully consume the underlying stream,
|
|
400
|
+
updating the Response with all collected content.
|
|
401
|
+
|
|
402
|
+
As content is consumed, it is cached on the StreamResponse. If a new iterator
|
|
403
|
+
is constructed via calling `streams()`, it will start by replaying the cached
|
|
404
|
+
content from the response, and (if there is still more content to consume from
|
|
405
|
+
the LLM), it will proceed to consume it once it has iterated through all the
|
|
406
|
+
cached chunks.
|
|
407
|
+
"""
|
|
408
|
+
chunk_iter = self.chunk_stream()
|
|
409
|
+
|
|
410
|
+
for start_chunk in chunk_iter:
|
|
411
|
+
# At the start of this loop, we always expect to find a start chunk. Then,
|
|
412
|
+
# before proceeding, we will collect from the stream we create (in case the
|
|
413
|
+
# user did not exhaust it), which ensures we will be expecting a start chunk
|
|
414
|
+
# again on the next iteration
|
|
415
|
+
match start_chunk.type:
|
|
416
|
+
case "text_start_chunk":
|
|
417
|
+
|
|
418
|
+
def text_stream_iterator() -> Iterator[TextChunk]:
|
|
419
|
+
for chunk in chunk_iter:
|
|
420
|
+
if chunk.type == "text_chunk":
|
|
421
|
+
yield chunk
|
|
422
|
+
else:
|
|
423
|
+
return # Stream finished
|
|
424
|
+
|
|
425
|
+
stream = TextStream(chunk_iterator=text_stream_iterator())
|
|
426
|
+
yield stream
|
|
427
|
+
|
|
428
|
+
case "thought_start_chunk":
|
|
429
|
+
|
|
430
|
+
def thought_stream_iterator() -> Iterator[ThoughtChunk]:
|
|
431
|
+
for chunk in chunk_iter:
|
|
432
|
+
if chunk.type == "thought_chunk":
|
|
433
|
+
yield chunk
|
|
434
|
+
else:
|
|
435
|
+
return # Stream finished
|
|
436
|
+
|
|
437
|
+
stream = ThoughtStream(chunk_iterator=thought_stream_iterator())
|
|
438
|
+
yield stream
|
|
439
|
+
|
|
440
|
+
case "tool_call_start_chunk":
|
|
441
|
+
tool_id = start_chunk.id
|
|
442
|
+
tool_name = start_chunk.name
|
|
443
|
+
|
|
444
|
+
def tool_call_stream_iterator() -> Iterator[ToolCallChunk]:
|
|
445
|
+
for chunk in chunk_iter:
|
|
446
|
+
if chunk.type == "tool_call_chunk":
|
|
447
|
+
yield chunk
|
|
448
|
+
else:
|
|
449
|
+
return # Stream finished
|
|
450
|
+
|
|
451
|
+
stream = ToolCallStream(
|
|
452
|
+
tool_id=tool_id,
|
|
453
|
+
tool_name=tool_name,
|
|
454
|
+
chunk_iterator=tool_call_stream_iterator(),
|
|
455
|
+
)
|
|
456
|
+
yield stream
|
|
457
|
+
|
|
458
|
+
case _: # pragma: no cover
|
|
459
|
+
raise RuntimeError(f"Expected start chunk, got: {start_chunk.type}")
|
|
460
|
+
|
|
461
|
+
# Before continuing to the next stream, make sure the last stream is consumed
|
|
462
|
+
# (If the user did not do so when we yielded it)
|
|
463
|
+
stream.collect()
|
|
464
|
+
|
|
465
|
+
def chunk_stream(
|
|
466
|
+
self,
|
|
467
|
+
) -> Iterator[AssistantContentChunk]:
|
|
468
|
+
"""Returns an iterator that yields content chunks as they are received.
|
|
469
|
+
|
|
470
|
+
Returns:
|
|
471
|
+
Iterator[AssistantContentChunk]: Synchronous iterator yielding chunks
|
|
472
|
+
|
|
473
|
+
This provides access to the Mirascope chunk data including start, delta, and end chunks
|
|
474
|
+
for each content type (text, thought, tool_call). Unlike the streams() method
|
|
475
|
+
that groups chunks by content part, this yields individual chunks as they arrive.
|
|
476
|
+
|
|
477
|
+
Fully iterating through this iterator will fully consume the underlying stream,
|
|
478
|
+
updating the Response with all collected content.
|
|
479
|
+
|
|
480
|
+
As chunks are consumed, they are cached on the StreamResponse. If a new iterator
|
|
481
|
+
is constructed via calling `chunk_stream()`, it will start by replaying the cached
|
|
482
|
+
chunks from the response, and (if there is still more content to consume from
|
|
483
|
+
the LLM), it will proceed to consume it once it has iterated through all the
|
|
484
|
+
cached chunks.
|
|
485
|
+
"""
|
|
486
|
+
for chunk in self.chunks:
|
|
487
|
+
yield chunk
|
|
488
|
+
|
|
489
|
+
if self.consumed:
|
|
490
|
+
return
|
|
491
|
+
|
|
492
|
+
for chunk in self._chunk_iterator:
|
|
493
|
+
if chunk.type == "raw_stream_event_chunk":
|
|
494
|
+
self._raw_stream_events.append(chunk.raw_stream_event)
|
|
495
|
+
elif chunk.type == "raw_message_chunk":
|
|
496
|
+
self._assistant_message.raw_message = chunk.raw_message
|
|
497
|
+
elif chunk.type == "finish_reason_chunk":
|
|
498
|
+
self.finish_reason = chunk.finish_reason
|
|
499
|
+
elif chunk.type == "usage_delta_chunk":
|
|
500
|
+
if self.usage is None:
|
|
501
|
+
self.usage = Usage()
|
|
502
|
+
self.usage.input_tokens += chunk.input_tokens
|
|
503
|
+
self.usage.output_tokens += chunk.output_tokens
|
|
504
|
+
self.usage.cache_read_tokens += chunk.cache_read_tokens
|
|
505
|
+
self.usage.cache_write_tokens += chunk.cache_write_tokens
|
|
506
|
+
self.usage.reasoning_tokens += chunk.reasoning_tokens
|
|
507
|
+
if chunk.provider_tool_usage:
|
|
508
|
+
self.usage.provider_tool_usage = chunk.provider_tool_usage
|
|
509
|
+
else:
|
|
510
|
+
yield self._handle_chunk(chunk)
|
|
511
|
+
|
|
512
|
+
self.consumed = True
|
|
513
|
+
|
|
514
|
+
def finish(self) -> None:
|
|
515
|
+
"""Finish streaming all of this response's content."""
|
|
516
|
+
for _ in self.chunk_stream():
|
|
517
|
+
pass
|
|
518
|
+
|
|
519
|
+
def text_stream(self, sep: str = "\n") -> Iterator[str]:
|
|
520
|
+
"""Stream only the text content from the response.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
sep: Separator to yield between text parts. Defaults to newline.
|
|
524
|
+
|
|
525
|
+
Returns:
|
|
526
|
+
Iterator[str]: Iterator yielding text delta strings
|
|
527
|
+
|
|
528
|
+
Yields text deltas as they arrive, ignoring thoughts, tool calls, and other
|
|
529
|
+
content types. Ideal for displaying text to users in real-time.
|
|
530
|
+
|
|
531
|
+
If you concatenate the strings from `.text_stream()`, it will be equivalent to
|
|
532
|
+
calling `.text(sep=sep)` on the fully consumed response.
|
|
533
|
+
"""
|
|
534
|
+
for stream in self.streams():
|
|
535
|
+
if stream.content_type == "text":
|
|
536
|
+
yield from stream
|
|
537
|
+
yield sep
|
|
538
|
+
|
|
539
|
+
def pretty_stream(self) -> Iterator[str]:
|
|
540
|
+
"""Stream a readable representation of the stream_response as text.
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
Iterator[str]: Iterator yielding string chunks depicting the content
|
|
544
|
+
|
|
545
|
+
Iterating through the pretty stream will populate the stream response by consuming
|
|
546
|
+
the underlying iterator (if it hasn't been consumed already). Calling `.pretty_stream()`
|
|
547
|
+
will always return a fresh iterator that begins from the start of the stream.
|
|
548
|
+
|
|
549
|
+
If you concatenate the text from `.pretty_stream()`, it will be equivalent to the
|
|
550
|
+
text generated by calling `.pretty()` (assuming the response was fully consumed
|
|
551
|
+
at the time when you call `.pretty()`).
|
|
552
|
+
"""
|
|
553
|
+
printed = False
|
|
554
|
+
|
|
555
|
+
for chunk in self.chunk_stream():
|
|
556
|
+
pretty = self._pretty_chunk(chunk, "\n\n" if printed else "")
|
|
557
|
+
if pretty != "":
|
|
558
|
+
printed = True
|
|
559
|
+
yield pretty
|
|
560
|
+
|
|
561
|
+
def structured_stream(
|
|
562
|
+
self,
|
|
563
|
+
) -> Iterator[Partial[FormattableT]]:
|
|
564
|
+
"""Drive the stream forward, yielding partial formatted outputs as they arrive.
|
|
565
|
+
|
|
566
|
+
This method consumes the underlying stream chunk by chunk, yielding parsed
|
|
567
|
+
partial outputs each time new content arrives. Each yielded value is a
|
|
568
|
+
Partial[FormattableT] with optional fields that may be None until fully received.
|
|
569
|
+
|
|
570
|
+
Example:
|
|
571
|
+
>>> response = recommend_book.stream("fantasy")
|
|
572
|
+
>>> for partial in response.structured_stream():
|
|
573
|
+
>>> print(f"Title so far: {partial.title}")
|
|
574
|
+
>>> book = response.parse() # Get final complete result
|
|
575
|
+
|
|
576
|
+
Fully iterating through this iterator will fully consume the underlying stream,
|
|
577
|
+
updating the Response with all collected content.
|
|
578
|
+
|
|
579
|
+
Yields:
|
|
580
|
+
Partial[FormattableT]: Partial objects with fields populated as they arrive.
|
|
581
|
+
Fields not yet received will be None.
|
|
582
|
+
|
|
583
|
+
Raises:
|
|
584
|
+
ValueError: If format parameter not set.
|
|
585
|
+
NotImplementedError: If format uses OutputParser (not supported).
|
|
586
|
+
"""
|
|
587
|
+
if self.format is None:
|
|
588
|
+
raise ValueError("structured_stream() requires format parameter")
|
|
589
|
+
|
|
590
|
+
if is_output_parser(self.format.formattable):
|
|
591
|
+
raise NotImplementedError(
|
|
592
|
+
"structured_stream() not supported for OutputParser. "
|
|
593
|
+
"Use BaseModel or primitive types."
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
for chunk in self.chunk_stream():
|
|
597
|
+
if chunk.type == "text_chunk":
|
|
598
|
+
partial = self.parse(partial=True)
|
|
599
|
+
if partial:
|
|
600
|
+
yield partial
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
class BaseAsyncStreamResponse(
|
|
604
|
+
BaseStreamResponse[AsyncChunkIterator, ToolkitT, FormattableT]
|
|
605
|
+
):
|
|
606
|
+
"""A base class for asynchronous Stream Responses."""
|
|
607
|
+
|
|
608
|
+
async def streams(self) -> AsyncIterator[AsyncStream]:
|
|
609
|
+
"""Returns an async iterator that yields streams for each content part in the response.
|
|
610
|
+
|
|
611
|
+
Returns:
|
|
612
|
+
AsyncIterator[AsyncStream]: Async iterator yielding AsyncStream objects
|
|
613
|
+
|
|
614
|
+
Each content part in the response will correspond to one stream, which will yield
|
|
615
|
+
chunks of content as they come in from the underlying LLM.
|
|
616
|
+
|
|
617
|
+
Fully iterating through this iterator will fully consume the underlying stream,
|
|
618
|
+
updating the Response with all collected content.
|
|
619
|
+
|
|
620
|
+
As content is consumed, it is cached on the AsyncStreamResponse. If a new iterator
|
|
621
|
+
is constructed via calling `streams()`, it will start by replaying the cached
|
|
622
|
+
content from the response, and (if there is still more content to consume from
|
|
623
|
+
the LLM), it will proceed to consume it once it has iterated through all the
|
|
624
|
+
cached chunks.
|
|
625
|
+
"""
|
|
626
|
+
chunk_iter = self.chunk_stream()
|
|
627
|
+
|
|
628
|
+
async for start_chunk in chunk_iter:
|
|
629
|
+
# At the start of this loop, we always expect to find a start chunk. Then,
|
|
630
|
+
# before proceeding, we will collect from the stream we create (in case the
|
|
631
|
+
# user did not exhaust it), which ensures we will be expecting a start chunk
|
|
632
|
+
# again on the next iteration
|
|
633
|
+
match start_chunk.type:
|
|
634
|
+
case "text_start_chunk":
|
|
635
|
+
|
|
636
|
+
async def text_stream_iterator() -> AsyncIterator[TextChunk]:
|
|
637
|
+
async for chunk in chunk_iter:
|
|
638
|
+
if chunk.type == "text_chunk":
|
|
639
|
+
yield chunk
|
|
640
|
+
else:
|
|
641
|
+
return # Stream finished
|
|
642
|
+
|
|
643
|
+
stream = AsyncTextStream(chunk_iterator=text_stream_iterator())
|
|
644
|
+
yield stream
|
|
645
|
+
|
|
646
|
+
case "thought_start_chunk":
|
|
647
|
+
|
|
648
|
+
async def thought_stream_iterator() -> AsyncIterator[ThoughtChunk]:
|
|
649
|
+
async for chunk in chunk_iter:
|
|
650
|
+
if chunk.type == "thought_chunk":
|
|
651
|
+
yield chunk
|
|
652
|
+
else:
|
|
653
|
+
return # Stream finished
|
|
654
|
+
|
|
655
|
+
stream = AsyncThoughtStream(
|
|
656
|
+
chunk_iterator=thought_stream_iterator()
|
|
657
|
+
)
|
|
658
|
+
yield stream
|
|
659
|
+
|
|
660
|
+
case "tool_call_start_chunk":
|
|
661
|
+
tool_id = start_chunk.id
|
|
662
|
+
tool_name = start_chunk.name
|
|
663
|
+
|
|
664
|
+
async def tool_call_stream_iterator() -> AsyncIterator[
|
|
665
|
+
ToolCallChunk
|
|
666
|
+
]:
|
|
667
|
+
async for chunk in chunk_iter:
|
|
668
|
+
if chunk.type == "tool_call_chunk":
|
|
669
|
+
yield chunk
|
|
670
|
+
else:
|
|
671
|
+
return # Stream finished
|
|
672
|
+
|
|
673
|
+
stream = AsyncToolCallStream(
|
|
674
|
+
tool_id=tool_id,
|
|
675
|
+
tool_name=tool_name,
|
|
676
|
+
chunk_iterator=tool_call_stream_iterator(),
|
|
677
|
+
)
|
|
678
|
+
yield stream
|
|
679
|
+
|
|
680
|
+
case _: # pragma: no cover
|
|
681
|
+
raise RuntimeError(f"Expected start chunk, got: {start_chunk.type}")
|
|
682
|
+
|
|
683
|
+
# Before continuing to the next stream, make sure the last stream is consumed
|
|
684
|
+
# (If the user did not do so when we yielded it)
|
|
685
|
+
await stream.collect()
|
|
686
|
+
|
|
687
|
+
async def chunk_stream(
|
|
688
|
+
self,
|
|
689
|
+
) -> AsyncIterator[AssistantContentChunk]:
|
|
690
|
+
"""Returns an async iterator that yields content chunks as they are received.
|
|
691
|
+
|
|
692
|
+
Returns:
|
|
693
|
+
AsyncIterator[AssistantContentChunk]: Async iterator yielding chunks
|
|
694
|
+
|
|
695
|
+
This provides access to the Mirascope chunk data including start, delta, and end chunks
|
|
696
|
+
for each content type (text, thinking, tool_call). Unlike the streams() method
|
|
697
|
+
that groups chunks by content part, this yields individual chunks as they arrive.
|
|
698
|
+
|
|
699
|
+
Fully iterating through this iterator will fully consume the underlying stream,
|
|
700
|
+
updating the Response with all collected content.
|
|
701
|
+
|
|
702
|
+
As chunks are consumed, they are cached on the AsyncStreamResponse. If a new iterator
|
|
703
|
+
is constructed via calling `chunk_stream()`, it will start by replaying the cached
|
|
704
|
+
chunks from the response, and (if there is still more content to consume from
|
|
705
|
+
the LLM), it will proceed to consume it once it has iterated through all the
|
|
706
|
+
cached chunks.
|
|
707
|
+
"""
|
|
708
|
+
|
|
709
|
+
for chunk in self.chunks:
|
|
710
|
+
yield chunk
|
|
711
|
+
|
|
712
|
+
if self.consumed:
|
|
713
|
+
return
|
|
714
|
+
|
|
715
|
+
async for chunk in self._chunk_iterator:
|
|
716
|
+
if chunk.type == "raw_stream_event_chunk":
|
|
717
|
+
self._raw_stream_events.append(chunk.raw_stream_event)
|
|
718
|
+
elif chunk.type == "raw_message_chunk":
|
|
719
|
+
self._assistant_message.raw_message = chunk.raw_message
|
|
720
|
+
elif chunk.type == "finish_reason_chunk":
|
|
721
|
+
self.finish_reason = chunk.finish_reason
|
|
722
|
+
elif chunk.type == "usage_delta_chunk":
|
|
723
|
+
if self.usage is None:
|
|
724
|
+
self.usage = Usage()
|
|
725
|
+
self.usage.input_tokens += chunk.input_tokens
|
|
726
|
+
self.usage.output_tokens += chunk.output_tokens
|
|
727
|
+
self.usage.cache_read_tokens += chunk.cache_read_tokens
|
|
728
|
+
self.usage.cache_write_tokens += chunk.cache_write_tokens
|
|
729
|
+
self.usage.reasoning_tokens += chunk.reasoning_tokens
|
|
730
|
+
if chunk.provider_tool_usage:
|
|
731
|
+
self.usage.provider_tool_usage = chunk.provider_tool_usage
|
|
732
|
+
else:
|
|
733
|
+
yield self._handle_chunk(chunk)
|
|
734
|
+
|
|
735
|
+
self.consumed = True
|
|
736
|
+
|
|
737
|
+
async def finish(self) -> None:
|
|
738
|
+
"""Finish streaming all of this response's content."""
|
|
739
|
+
async for _ in self.chunk_stream():
|
|
740
|
+
pass
|
|
741
|
+
|
|
742
|
+
async def text_stream(self, sep: str = "\n") -> AsyncIterator[str]:
|
|
743
|
+
"""Stream only the text content from the response.
|
|
744
|
+
|
|
745
|
+
Args:
|
|
746
|
+
sep: Separator to yield between text parts. Defaults to newline.
|
|
747
|
+
|
|
748
|
+
Returns:
|
|
749
|
+
AsyncIterator[str]: Async iterator yielding text delta strings
|
|
750
|
+
|
|
751
|
+
Yields text deltas as they arrive, ignoring thoughts, tool calls, and other
|
|
752
|
+
content types. Ideal for displaying text to users in real-time.
|
|
753
|
+
|
|
754
|
+
If you concatenate the strings from `.text_stream()`, it will be equivalent to
|
|
755
|
+
calling `.text(sep=sep)` on the fully consumed response.
|
|
756
|
+
"""
|
|
757
|
+
async for stream in self.streams():
|
|
758
|
+
if stream.content_type == "text":
|
|
759
|
+
async for delta in stream:
|
|
760
|
+
yield delta
|
|
761
|
+
yield sep
|
|
762
|
+
|
|
763
|
+
async def pretty_stream(self) -> AsyncIterator[str]:
|
|
764
|
+
"""Stream a readable representation of the stream_response as text.
|
|
765
|
+
|
|
766
|
+
Returns:
|
|
767
|
+
AsyncIterator[str]: Async iterator yielding string chunks depicting the content
|
|
768
|
+
|
|
769
|
+
Iterating through the pretty stream will populate the stream response by consuming
|
|
770
|
+
the underlying iterator (if it hasn't been consumed already). Calling `.pretty_stream()`
|
|
771
|
+
will always return a fresh iterator that begins from the start of the stream.
|
|
772
|
+
|
|
773
|
+
If you concatenate the text from `.pretty_stream()`, it will be equivalent to the
|
|
774
|
+
text generated by calling `.pretty()` (assuming the response was fully consumed
|
|
775
|
+
at the time when you call `.pretty()`).
|
|
776
|
+
"""
|
|
777
|
+
printed = False
|
|
778
|
+
|
|
779
|
+
async for chunk in self.chunk_stream():
|
|
780
|
+
pretty = self._pretty_chunk(chunk, "\n\n" if printed else "")
|
|
781
|
+
if pretty != "":
|
|
782
|
+
printed = True
|
|
783
|
+
yield pretty
|
|
784
|
+
|
|
785
|
+
async def structured_stream(
|
|
786
|
+
self,
|
|
787
|
+
) -> AsyncIterator[Partial[FormattableT]]:
|
|
788
|
+
"""Drive the stream forward, yielding partial formatted outputs as they arrive.
|
|
789
|
+
|
|
790
|
+
This method consumes the underlying stream chunk by chunk, yielding parsed
|
|
791
|
+
partial outputs each time new content arrives. Each yielded value is a
|
|
792
|
+
Partial[FormattableT] with optional fields that may be None until fully received.
|
|
793
|
+
|
|
794
|
+
Example:
|
|
795
|
+
>>> response = await recommend_book.stream("fantasy")
|
|
796
|
+
>>> async for partial in response.structured_stream():
|
|
797
|
+
>>> print(f"Title so far: {partial.title}")
|
|
798
|
+
>>> book = response.parse() # Get final complete result
|
|
799
|
+
|
|
800
|
+
Fully iterating through this iterator will fully consume the underlying stream,
|
|
801
|
+
updating the Response with all collected content.
|
|
802
|
+
|
|
803
|
+
Yields:
|
|
804
|
+
Partial[FormattableT]: Partial objects with fields populated as they arrive.
|
|
805
|
+
Fields not yet received will be None.
|
|
806
|
+
|
|
807
|
+
Raises:
|
|
808
|
+
ValueError: If format parameter not set.
|
|
809
|
+
NotImplementedError: If format uses OutputParser (not supported).
|
|
810
|
+
"""
|
|
811
|
+
if self.format is None:
|
|
812
|
+
raise ValueError("structured_stream() requires format parameter")
|
|
813
|
+
|
|
814
|
+
if is_output_parser(self.format.formattable):
|
|
815
|
+
raise NotImplementedError(
|
|
816
|
+
"structured_stream() not supported for OutputParser. "
|
|
817
|
+
"Use BaseModel or primitive types."
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
async for chunk in self.chunk_stream():
|
|
821
|
+
if chunk.type == "text_chunk":
|
|
822
|
+
partial = self.parse(partial=True)
|
|
823
|
+
if partial:
|
|
824
|
+
yield partial
|