mirascope 2.0.0__py3-none-any.whl → 2.0.0a0__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 +2 -11
- mirascope/graphs/__init__.py +22 -0
- mirascope/graphs/finite_state_machine.py +625 -0
- mirascope/llm/__init__.py +16 -101
- mirascope/llm/agents/__init__.py +15 -0
- mirascope/llm/agents/agent.py +97 -0
- mirascope/llm/agents/agent_template.py +45 -0
- mirascope/llm/agents/decorator.py +176 -0
- mirascope/llm/calls/__init__.py +1 -2
- mirascope/llm/calls/base_call.py +33 -0
- mirascope/llm/calls/calls.py +58 -84
- mirascope/llm/calls/decorator.py +120 -140
- mirascope/llm/clients/__init__.py +34 -0
- mirascope/llm/clients/anthropic/__init__.py +11 -0
- mirascope/llm/{providers/openai/completions → clients/anthropic}/_utils/__init__.py +0 -2
- mirascope/llm/{providers → clients}/anthropic/_utils/decode.py +22 -66
- mirascope/llm/clients/anthropic/_utils/encode.py +243 -0
- mirascope/llm/clients/anthropic/clients.py +819 -0
- mirascope/llm/clients/anthropic/model_ids.py +8 -0
- mirascope/llm/{providers → clients}/base/__init__.py +5 -4
- mirascope/llm/{providers → clients}/base/_utils.py +17 -78
- mirascope/llm/{providers/base/base_provider.py → clients/base/client.py} +145 -468
- mirascope/llm/{models → clients/base}/params.py +37 -16
- mirascope/llm/clients/google/__init__.py +6 -0
- mirascope/llm/{providers/openai/responses → clients/google}/_utils/__init__.py +0 -2
- mirascope/llm/{providers → clients}/google/_utils/decode.py +22 -98
- mirascope/llm/{providers → clients}/google/_utils/encode.py +46 -168
- mirascope/llm/clients/google/clients.py +853 -0
- mirascope/llm/clients/google/model_ids.py +15 -0
- mirascope/llm/clients/openai/__init__.py +25 -0
- mirascope/llm/clients/openai/completions/__init__.py +9 -0
- mirascope/llm/{providers/google → clients/openai/completions}/_utils/__init__.py +0 -4
- mirascope/llm/{providers → clients}/openai/completions/_utils/decode.py +9 -74
- mirascope/llm/{providers → clients}/openai/completions/_utils/encode.py +52 -70
- mirascope/llm/clients/openai/completions/_utils/model_features.py +81 -0
- mirascope/llm/clients/openai/completions/clients.py +833 -0
- mirascope/llm/clients/openai/completions/model_ids.py +8 -0
- mirascope/llm/clients/openai/responses/__init__.py +9 -0
- mirascope/llm/clients/openai/responses/_utils/__init__.py +13 -0
- mirascope/llm/{providers → clients}/openai/responses/_utils/decode.py +14 -80
- mirascope/llm/{providers → clients}/openai/responses/_utils/encode.py +41 -92
- mirascope/llm/clients/openai/responses/_utils/model_features.py +87 -0
- mirascope/llm/clients/openai/responses/clients.py +832 -0
- mirascope/llm/clients/openai/responses/model_ids.py +8 -0
- mirascope/llm/clients/openai/shared/__init__.py +7 -0
- mirascope/llm/clients/openai/shared/_utils.py +55 -0
- mirascope/llm/clients/providers.py +175 -0
- mirascope/llm/content/__init__.py +2 -3
- mirascope/llm/content/tool_call.py +0 -6
- mirascope/llm/content/tool_output.py +5 -22
- mirascope/llm/context/_utils.py +6 -19
- mirascope/llm/exceptions.py +43 -298
- mirascope/llm/formatting/__init__.py +2 -19
- mirascope/llm/formatting/_utils.py +74 -0
- mirascope/llm/formatting/format.py +30 -219
- mirascope/llm/formatting/from_call_args.py +2 -2
- mirascope/llm/formatting/partial.py +7 -80
- mirascope/llm/formatting/types.py +64 -21
- mirascope/llm/mcp/__init__.py +2 -2
- mirascope/llm/mcp/client.py +118 -0
- mirascope/llm/messages/__init__.py +0 -3
- mirascope/llm/messages/message.py +5 -13
- mirascope/llm/models/__init__.py +2 -7
- mirascope/llm/models/models.py +139 -315
- mirascope/llm/prompts/__init__.py +12 -13
- mirascope/llm/prompts/_utils.py +43 -14
- mirascope/llm/prompts/decorator.py +204 -144
- mirascope/llm/prompts/protocols.py +59 -25
- mirascope/llm/responses/__init__.py +1 -9
- mirascope/llm/responses/_utils.py +12 -102
- mirascope/llm/responses/base_response.py +6 -18
- mirascope/llm/responses/base_stream_response.py +50 -173
- mirascope/llm/responses/finish_reason.py +0 -1
- mirascope/llm/responses/response.py +13 -34
- mirascope/llm/responses/root_response.py +29 -100
- mirascope/llm/responses/stream_response.py +31 -40
- mirascope/llm/tools/__init__.py +2 -9
- mirascope/llm/tools/_utils.py +3 -12
- mirascope/llm/tools/decorator.py +16 -25
- mirascope/llm/tools/protocols.py +4 -4
- mirascope/llm/tools/tool_schema.py +19 -87
- mirascope/llm/tools/toolkit.py +27 -35
- mirascope/llm/tools/tools.py +41 -135
- {mirascope-2.0.0.dist-info → mirascope-2.0.0a0.dist-info}/METADATA +9 -95
- mirascope-2.0.0a0.dist-info/RECORD +101 -0
- {mirascope-2.0.0.dist-info → mirascope-2.0.0a0.dist-info}/WHEEL +1 -1
- {mirascope-2.0.0.dist-info → mirascope-2.0.0a0.dist-info}/licenses/LICENSE +1 -1
- mirascope/_stubs.py +0 -363
- mirascope/api/__init__.py +0 -14
- mirascope/api/_generated/README.md +0 -207
- mirascope/api/_generated/__init__.py +0 -440
- mirascope/api/_generated/annotations/__init__.py +0 -33
- mirascope/api/_generated/annotations/client.py +0 -506
- mirascope/api/_generated/annotations/raw_client.py +0 -1414
- mirascope/api/_generated/annotations/types/__init__.py +0 -31
- mirascope/api/_generated/annotations/types/annotations_create_request_label.py +0 -5
- mirascope/api/_generated/annotations/types/annotations_create_response.py +0 -48
- mirascope/api/_generated/annotations/types/annotations_create_response_label.py +0 -5
- mirascope/api/_generated/annotations/types/annotations_get_response.py +0 -48
- mirascope/api/_generated/annotations/types/annotations_get_response_label.py +0 -5
- mirascope/api/_generated/annotations/types/annotations_list_request_label.py +0 -5
- mirascope/api/_generated/annotations/types/annotations_list_response.py +0 -21
- mirascope/api/_generated/annotations/types/annotations_list_response_annotations_item.py +0 -50
- mirascope/api/_generated/annotations/types/annotations_list_response_annotations_item_label.py +0 -5
- mirascope/api/_generated/annotations/types/annotations_update_request_label.py +0 -5
- mirascope/api/_generated/annotations/types/annotations_update_response.py +0 -48
- mirascope/api/_generated/annotations/types/annotations_update_response_label.py +0 -5
- mirascope/api/_generated/api_keys/__init__.py +0 -17
- mirascope/api/_generated/api_keys/client.py +0 -530
- mirascope/api/_generated/api_keys/raw_client.py +0 -1236
- mirascope/api/_generated/api_keys/types/__init__.py +0 -15
- mirascope/api/_generated/api_keys/types/api_keys_create_response.py +0 -28
- mirascope/api/_generated/api_keys/types/api_keys_get_response.py +0 -27
- mirascope/api/_generated/api_keys/types/api_keys_list_all_for_org_response_item.py +0 -40
- mirascope/api/_generated/api_keys/types/api_keys_list_response_item.py +0 -27
- mirascope/api/_generated/client.py +0 -211
- mirascope/api/_generated/core/__init__.py +0 -52
- mirascope/api/_generated/core/api_error.py +0 -23
- mirascope/api/_generated/core/client_wrapper.py +0 -46
- mirascope/api/_generated/core/datetime_utils.py +0 -28
- mirascope/api/_generated/core/file.py +0 -67
- mirascope/api/_generated/core/force_multipart.py +0 -16
- mirascope/api/_generated/core/http_client.py +0 -543
- mirascope/api/_generated/core/http_response.py +0 -55
- mirascope/api/_generated/core/jsonable_encoder.py +0 -100
- mirascope/api/_generated/core/pydantic_utilities.py +0 -255
- mirascope/api/_generated/core/query_encoder.py +0 -58
- mirascope/api/_generated/core/remove_none_from_dict.py +0 -11
- mirascope/api/_generated/core/request_options.py +0 -35
- mirascope/api/_generated/core/serialization.py +0 -276
- mirascope/api/_generated/docs/__init__.py +0 -4
- mirascope/api/_generated/docs/client.py +0 -91
- mirascope/api/_generated/docs/raw_client.py +0 -178
- mirascope/api/_generated/environment.py +0 -9
- mirascope/api/_generated/environments/__init__.py +0 -23
- mirascope/api/_generated/environments/client.py +0 -649
- mirascope/api/_generated/environments/raw_client.py +0 -1567
- mirascope/api/_generated/environments/types/__init__.py +0 -25
- mirascope/api/_generated/environments/types/environments_create_response.py +0 -24
- mirascope/api/_generated/environments/types/environments_get_analytics_response.py +0 -60
- mirascope/api/_generated/environments/types/environments_get_analytics_response_top_functions_item.py +0 -24
- mirascope/api/_generated/environments/types/environments_get_analytics_response_top_models_item.py +0 -22
- mirascope/api/_generated/environments/types/environments_get_response.py +0 -24
- mirascope/api/_generated/environments/types/environments_list_response_item.py +0 -24
- mirascope/api/_generated/environments/types/environments_update_response.py +0 -24
- mirascope/api/_generated/errors/__init__.py +0 -25
- mirascope/api/_generated/errors/bad_request_error.py +0 -14
- mirascope/api/_generated/errors/conflict_error.py +0 -14
- mirascope/api/_generated/errors/forbidden_error.py +0 -11
- mirascope/api/_generated/errors/internal_server_error.py +0 -10
- mirascope/api/_generated/errors/not_found_error.py +0 -11
- mirascope/api/_generated/errors/payment_required_error.py +0 -15
- mirascope/api/_generated/errors/service_unavailable_error.py +0 -14
- mirascope/api/_generated/errors/too_many_requests_error.py +0 -15
- mirascope/api/_generated/errors/unauthorized_error.py +0 -11
- mirascope/api/_generated/functions/__init__.py +0 -39
- mirascope/api/_generated/functions/client.py +0 -647
- mirascope/api/_generated/functions/raw_client.py +0 -1890
- mirascope/api/_generated/functions/types/__init__.py +0 -53
- mirascope/api/_generated/functions/types/functions_create_request_dependencies_value.py +0 -20
- mirascope/api/_generated/functions/types/functions_create_response.py +0 -37
- mirascope/api/_generated/functions/types/functions_create_response_dependencies_value.py +0 -20
- mirascope/api/_generated/functions/types/functions_find_by_hash_response.py +0 -39
- mirascope/api/_generated/functions/types/functions_find_by_hash_response_dependencies_value.py +0 -20
- mirascope/api/_generated/functions/types/functions_get_by_env_response.py +0 -53
- mirascope/api/_generated/functions/types/functions_get_by_env_response_dependencies_value.py +0 -22
- mirascope/api/_generated/functions/types/functions_get_response.py +0 -37
- mirascope/api/_generated/functions/types/functions_get_response_dependencies_value.py +0 -20
- mirascope/api/_generated/functions/types/functions_list_by_env_response.py +0 -25
- mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item.py +0 -56
- mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item_dependencies_value.py +0 -22
- mirascope/api/_generated/functions/types/functions_list_response.py +0 -21
- mirascope/api/_generated/functions/types/functions_list_response_functions_item.py +0 -41
- mirascope/api/_generated/functions/types/functions_list_response_functions_item_dependencies_value.py +0 -20
- mirascope/api/_generated/health/__init__.py +0 -7
- mirascope/api/_generated/health/client.py +0 -92
- mirascope/api/_generated/health/raw_client.py +0 -175
- mirascope/api/_generated/health/types/__init__.py +0 -8
- mirascope/api/_generated/health/types/health_check_response.py +0 -22
- mirascope/api/_generated/health/types/health_check_response_status.py +0 -5
- mirascope/api/_generated/organization_invitations/__init__.py +0 -33
- mirascope/api/_generated/organization_invitations/client.py +0 -546
- mirascope/api/_generated/organization_invitations/raw_client.py +0 -1519
- mirascope/api/_generated/organization_invitations/types/__init__.py +0 -53
- mirascope/api/_generated/organization_invitations/types/organization_invitations_accept_response.py +0 -34
- mirascope/api/_generated/organization_invitations/types/organization_invitations_accept_response_role.py +0 -7
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_request_role.py +0 -7
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response.py +0 -48
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response_role.py +0 -7
- mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response_status.py +0 -7
- mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response.py +0 -48
- mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response_role.py +0 -7
- mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response_status.py +0 -7
- mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item.py +0 -48
- mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item_role.py +0 -7
- mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item_status.py +0 -7
- mirascope/api/_generated/organization_memberships/__init__.py +0 -19
- mirascope/api/_generated/organization_memberships/client.py +0 -302
- mirascope/api/_generated/organization_memberships/raw_client.py +0 -736
- mirascope/api/_generated/organization_memberships/types/__init__.py +0 -27
- mirascope/api/_generated/organization_memberships/types/organization_memberships_list_response_item.py +0 -33
- mirascope/api/_generated/organization_memberships/types/organization_memberships_list_response_item_role.py +0 -7
- mirascope/api/_generated/organization_memberships/types/organization_memberships_update_request_role.py +0 -7
- mirascope/api/_generated/organization_memberships/types/organization_memberships_update_response.py +0 -31
- mirascope/api/_generated/organization_memberships/types/organization_memberships_update_response_role.py +0 -7
- mirascope/api/_generated/organizations/__init__.py +0 -51
- mirascope/api/_generated/organizations/client.py +0 -869
- mirascope/api/_generated/organizations/raw_client.py +0 -2593
- mirascope/api/_generated/organizations/types/__init__.py +0 -71
- mirascope/api/_generated/organizations/types/organizations_create_payment_intent_response.py +0 -24
- mirascope/api/_generated/organizations/types/organizations_create_response.py +0 -26
- mirascope/api/_generated/organizations/types/organizations_create_response_role.py +0 -5
- mirascope/api/_generated/organizations/types/organizations_get_response.py +0 -26
- mirascope/api/_generated/organizations/types/organizations_get_response_role.py +0 -5
- mirascope/api/_generated/organizations/types/organizations_list_response_item.py +0 -26
- mirascope/api/_generated/organizations/types/organizations_list_response_item_role.py +0 -5
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_request_target_plan.py +0 -7
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response.py +0 -47
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response_validation_errors_item.py +0 -33
- mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response_validation_errors_item_resource.py +0 -7
- mirascope/api/_generated/organizations/types/organizations_router_balance_response.py +0 -24
- mirascope/api/_generated/organizations/types/organizations_subscription_response.py +0 -53
- mirascope/api/_generated/organizations/types/organizations_subscription_response_current_plan.py +0 -7
- mirascope/api/_generated/organizations/types/organizations_subscription_response_payment_method.py +0 -26
- mirascope/api/_generated/organizations/types/organizations_subscription_response_scheduled_change.py +0 -34
- mirascope/api/_generated/organizations/types/organizations_subscription_response_scheduled_change_target_plan.py +0 -7
- mirascope/api/_generated/organizations/types/organizations_update_response.py +0 -26
- mirascope/api/_generated/organizations/types/organizations_update_response_role.py +0 -5
- mirascope/api/_generated/organizations/types/organizations_update_subscription_request_target_plan.py +0 -7
- mirascope/api/_generated/organizations/types/organizations_update_subscription_response.py +0 -35
- mirascope/api/_generated/project_memberships/__init__.py +0 -25
- mirascope/api/_generated/project_memberships/client.py +0 -437
- mirascope/api/_generated/project_memberships/raw_client.py +0 -1039
- mirascope/api/_generated/project_memberships/types/__init__.py +0 -29
- mirascope/api/_generated/project_memberships/types/project_memberships_create_request_role.py +0 -7
- mirascope/api/_generated/project_memberships/types/project_memberships_create_response.py +0 -35
- mirascope/api/_generated/project_memberships/types/project_memberships_create_response_role.py +0 -7
- mirascope/api/_generated/project_memberships/types/project_memberships_list_response_item.py +0 -33
- mirascope/api/_generated/project_memberships/types/project_memberships_list_response_item_role.py +0 -7
- mirascope/api/_generated/project_memberships/types/project_memberships_update_request_role.py +0 -7
- mirascope/api/_generated/project_memberships/types/project_memberships_update_response.py +0 -35
- mirascope/api/_generated/project_memberships/types/project_memberships_update_response_role.py +0 -7
- mirascope/api/_generated/projects/__init__.py +0 -7
- mirascope/api/_generated/projects/client.py +0 -428
- mirascope/api/_generated/projects/raw_client.py +0 -1302
- mirascope/api/_generated/projects/types/__init__.py +0 -10
- mirascope/api/_generated/projects/types/projects_create_response.py +0 -25
- mirascope/api/_generated/projects/types/projects_get_response.py +0 -25
- mirascope/api/_generated/projects/types/projects_list_response_item.py +0 -25
- mirascope/api/_generated/projects/types/projects_update_response.py +0 -25
- mirascope/api/_generated/reference.md +0 -4915
- mirascope/api/_generated/tags/__init__.py +0 -19
- mirascope/api/_generated/tags/client.py +0 -504
- mirascope/api/_generated/tags/raw_client.py +0 -1288
- mirascope/api/_generated/tags/types/__init__.py +0 -17
- mirascope/api/_generated/tags/types/tags_create_response.py +0 -41
- mirascope/api/_generated/tags/types/tags_get_response.py +0 -41
- mirascope/api/_generated/tags/types/tags_list_response.py +0 -23
- mirascope/api/_generated/tags/types/tags_list_response_tags_item.py +0 -41
- mirascope/api/_generated/tags/types/tags_update_response.py +0 -41
- mirascope/api/_generated/token_cost/__init__.py +0 -7
- mirascope/api/_generated/token_cost/client.py +0 -160
- mirascope/api/_generated/token_cost/raw_client.py +0 -264
- mirascope/api/_generated/token_cost/types/__init__.py +0 -8
- mirascope/api/_generated/token_cost/types/token_cost_calculate_request_usage.py +0 -54
- mirascope/api/_generated/token_cost/types/token_cost_calculate_response.py +0 -52
- mirascope/api/_generated/traces/__init__.py +0 -97
- mirascope/api/_generated/traces/client.py +0 -1103
- mirascope/api/_generated/traces/raw_client.py +0 -2322
- mirascope/api/_generated/traces/types/__init__.py +0 -155
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item.py +0 -29
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource.py +0 -27
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item.py +0 -23
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value.py +0 -38
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_array_value.py +0 -19
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_kvlist_value.py +0 -22
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_kvlist_value_values_item.py +0 -20
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item.py +0 -29
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope.py +0 -31
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item.py +0 -23
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value.py +0 -38
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_array_value.py +0 -19
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_kvlist_value.py +0 -22
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_kvlist_value_values_item.py +0 -22
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item.py +0 -48
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item.py +0 -23
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value.py +0 -38
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_array_value.py +0 -19
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_kvlist_value.py +0 -24
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_kvlist_value_values_item.py +0 -22
- mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_status.py +0 -20
- mirascope/api/_generated/traces/types/traces_create_response.py +0 -24
- mirascope/api/_generated/traces/types/traces_create_response_partial_success.py +0 -22
- mirascope/api/_generated/traces/types/traces_get_analytics_summary_response.py +0 -60
- mirascope/api/_generated/traces/types/traces_get_analytics_summary_response_top_functions_item.py +0 -24
- mirascope/api/_generated/traces/types/traces_get_analytics_summary_response_top_models_item.py +0 -22
- mirascope/api/_generated/traces/types/traces_get_trace_detail_by_env_response.py +0 -33
- mirascope/api/_generated/traces/types/traces_get_trace_detail_by_env_response_spans_item.py +0 -88
- mirascope/api/_generated/traces/types/traces_get_trace_detail_response.py +0 -33
- mirascope/api/_generated/traces/types/traces_get_trace_detail_response_spans_item.py +0 -88
- mirascope/api/_generated/traces/types/traces_list_by_function_hash_response.py +0 -25
- mirascope/api/_generated/traces/types/traces_list_by_function_hash_response_traces_item.py +0 -44
- mirascope/api/_generated/traces/types/traces_search_by_env_request_attribute_filters_item.py +0 -26
- mirascope/api/_generated/traces/types/traces_search_by_env_request_attribute_filters_item_operator.py +0 -7
- mirascope/api/_generated/traces/types/traces_search_by_env_request_sort_by.py +0 -7
- mirascope/api/_generated/traces/types/traces_search_by_env_request_sort_order.py +0 -7
- mirascope/api/_generated/traces/types/traces_search_by_env_response.py +0 -26
- mirascope/api/_generated/traces/types/traces_search_by_env_response_spans_item.py +0 -50
- mirascope/api/_generated/traces/types/traces_search_request_attribute_filters_item.py +0 -26
- mirascope/api/_generated/traces/types/traces_search_request_attribute_filters_item_operator.py +0 -7
- mirascope/api/_generated/traces/types/traces_search_request_sort_by.py +0 -7
- mirascope/api/_generated/traces/types/traces_search_request_sort_order.py +0 -5
- mirascope/api/_generated/traces/types/traces_search_response.py +0 -26
- mirascope/api/_generated/traces/types/traces_search_response_spans_item.py +0 -50
- mirascope/api/_generated/types/__init__.py +0 -85
- mirascope/api/_generated/types/already_exists_error.py +0 -22
- mirascope/api/_generated/types/already_exists_error_tag.py +0 -5
- mirascope/api/_generated/types/bad_request_error_body.py +0 -50
- mirascope/api/_generated/types/click_house_error.py +0 -22
- mirascope/api/_generated/types/database_error.py +0 -22
- mirascope/api/_generated/types/database_error_tag.py +0 -5
- mirascope/api/_generated/types/date.py +0 -3
- mirascope/api/_generated/types/http_api_decode_error.py +0 -27
- mirascope/api/_generated/types/http_api_decode_error_tag.py +0 -5
- mirascope/api/_generated/types/immutable_resource_error.py +0 -22
- mirascope/api/_generated/types/internal_server_error_body.py +0 -49
- mirascope/api/_generated/types/issue.py +0 -38
- mirascope/api/_generated/types/issue_tag.py +0 -10
- mirascope/api/_generated/types/not_found_error_body.py +0 -22
- mirascope/api/_generated/types/not_found_error_tag.py +0 -5
- mirascope/api/_generated/types/number_from_string.py +0 -3
- mirascope/api/_generated/types/permission_denied_error.py +0 -22
- mirascope/api/_generated/types/permission_denied_error_tag.py +0 -5
- mirascope/api/_generated/types/plan_limit_exceeded_error.py +0 -32
- mirascope/api/_generated/types/plan_limit_exceeded_error_tag.py +0 -7
- mirascope/api/_generated/types/pricing_unavailable_error.py +0 -23
- mirascope/api/_generated/types/property_key.py +0 -7
- mirascope/api/_generated/types/property_key_key.py +0 -25
- mirascope/api/_generated/types/property_key_key_tag.py +0 -5
- mirascope/api/_generated/types/rate_limit_error.py +0 -31
- mirascope/api/_generated/types/rate_limit_error_tag.py +0 -5
- mirascope/api/_generated/types/service_unavailable_error_body.py +0 -24
- mirascope/api/_generated/types/service_unavailable_error_tag.py +0 -7
- mirascope/api/_generated/types/stripe_error.py +0 -20
- mirascope/api/_generated/types/subscription_past_due_error.py +0 -31
- mirascope/api/_generated/types/subscription_past_due_error_tag.py +0 -7
- mirascope/api/_generated/types/unauthorized_error_body.py +0 -21
- mirascope/api/_generated/types/unauthorized_error_tag.py +0 -5
- mirascope/api/client.py +0 -255
- mirascope/api/settings.py +0 -99
- mirascope/llm/formatting/output_parser.py +0 -178
- mirascope/llm/formatting/primitives.py +0 -192
- mirascope/llm/mcp/mcp_client.py +0 -130
- mirascope/llm/messages/_utils.py +0 -34
- mirascope/llm/models/thinking_config.py +0 -61
- mirascope/llm/prompts/prompts.py +0 -487
- mirascope/llm/providers/__init__.py +0 -62
- mirascope/llm/providers/anthropic/__init__.py +0 -11
- mirascope/llm/providers/anthropic/_utils/__init__.py +0 -27
- mirascope/llm/providers/anthropic/_utils/beta_decode.py +0 -282
- mirascope/llm/providers/anthropic/_utils/beta_encode.py +0 -266
- mirascope/llm/providers/anthropic/_utils/encode.py +0 -418
- mirascope/llm/providers/anthropic/_utils/errors.py +0 -46
- mirascope/llm/providers/anthropic/beta_provider.py +0 -374
- mirascope/llm/providers/anthropic/model_id.py +0 -23
- mirascope/llm/providers/anthropic/model_info.py +0 -87
- mirascope/llm/providers/anthropic/provider.py +0 -479
- mirascope/llm/providers/google/__init__.py +0 -6
- mirascope/llm/providers/google/_utils/errors.py +0 -50
- mirascope/llm/providers/google/model_id.py +0 -22
- mirascope/llm/providers/google/model_info.py +0 -63
- mirascope/llm/providers/google/provider.py +0 -492
- mirascope/llm/providers/mirascope/__init__.py +0 -5
- mirascope/llm/providers/mirascope/_utils.py +0 -73
- mirascope/llm/providers/mirascope/provider.py +0 -349
- mirascope/llm/providers/mlx/__init__.py +0 -9
- mirascope/llm/providers/mlx/_utils.py +0 -141
- mirascope/llm/providers/mlx/encoding/__init__.py +0 -8
- mirascope/llm/providers/mlx/encoding/base.py +0 -72
- mirascope/llm/providers/mlx/encoding/transformers.py +0 -150
- mirascope/llm/providers/mlx/mlx.py +0 -254
- mirascope/llm/providers/mlx/model_id.py +0 -17
- mirascope/llm/providers/mlx/provider.py +0 -452
- mirascope/llm/providers/model_id.py +0 -16
- mirascope/llm/providers/ollama/__init__.py +0 -7
- mirascope/llm/providers/ollama/provider.py +0 -71
- mirascope/llm/providers/openai/__init__.py +0 -15
- mirascope/llm/providers/openai/_utils/__init__.py +0 -5
- mirascope/llm/providers/openai/_utils/errors.py +0 -46
- mirascope/llm/providers/openai/completions/__init__.py +0 -7
- mirascope/llm/providers/openai/completions/base_provider.py +0 -542
- mirascope/llm/providers/openai/completions/provider.py +0 -22
- mirascope/llm/providers/openai/model_id.py +0 -31
- mirascope/llm/providers/openai/model_info.py +0 -303
- mirascope/llm/providers/openai/provider.py +0 -441
- mirascope/llm/providers/openai/responses/__init__.py +0 -5
- mirascope/llm/providers/openai/responses/provider.py +0 -513
- mirascope/llm/providers/provider_id.py +0 -24
- mirascope/llm/providers/provider_registry.py +0 -299
- mirascope/llm/providers/together/__init__.py +0 -7
- mirascope/llm/providers/together/provider.py +0 -40
- mirascope/llm/responses/usage.py +0 -95
- mirascope/ops/__init__.py +0 -111
- mirascope/ops/_internal/__init__.py +0 -5
- mirascope/ops/_internal/closure.py +0 -1169
- mirascope/ops/_internal/configuration.py +0 -177
- mirascope/ops/_internal/context.py +0 -76
- mirascope/ops/_internal/exporters/__init__.py +0 -26
- mirascope/ops/_internal/exporters/exporters.py +0 -395
- mirascope/ops/_internal/exporters/processors.py +0 -104
- mirascope/ops/_internal/exporters/types.py +0 -165
- mirascope/ops/_internal/exporters/utils.py +0 -29
- mirascope/ops/_internal/instrumentation/__init__.py +0 -8
- mirascope/ops/_internal/instrumentation/llm/__init__.py +0 -8
- mirascope/ops/_internal/instrumentation/llm/common.py +0 -530
- mirascope/ops/_internal/instrumentation/llm/cost.py +0 -190
- mirascope/ops/_internal/instrumentation/llm/encode.py +0 -238
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/__init__.py +0 -38
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_input_messages.py +0 -31
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_output_messages.py +0 -38
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_system_instructions.py +0 -18
- mirascope/ops/_internal/instrumentation/llm/gen_ai_types/shared.py +0 -100
- mirascope/ops/_internal/instrumentation/llm/llm.py +0 -161
- mirascope/ops/_internal/instrumentation/llm/model.py +0 -1798
- mirascope/ops/_internal/instrumentation/llm/response.py +0 -521
- mirascope/ops/_internal/instrumentation/llm/serialize.py +0 -300
- mirascope/ops/_internal/propagation.py +0 -198
- mirascope/ops/_internal/protocols.py +0 -133
- mirascope/ops/_internal/session.py +0 -139
- mirascope/ops/_internal/spans.py +0 -232
- mirascope/ops/_internal/traced_calls.py +0 -375
- mirascope/ops/_internal/traced_functions.py +0 -523
- mirascope/ops/_internal/tracing.py +0 -353
- mirascope/ops/_internal/types.py +0 -13
- mirascope/ops/_internal/utils.py +0 -123
- mirascope/ops/_internal/versioned_calls.py +0 -512
- mirascope/ops/_internal/versioned_functions.py +0 -357
- mirascope/ops/_internal/versioning.py +0 -303
- mirascope/ops/exceptions.py +0 -21
- mirascope-2.0.0.dist-info/RECORD +0 -423
- /mirascope/llm/{providers → clients}/base/kwargs.py +0 -0
- /mirascope/llm/{providers → clients}/google/message.py +0 -0
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
"""Mirascope-specific serialization for span attributes."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import logging
|
|
6
|
-
from collections.abc import Sequence
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Protocol
|
|
8
|
-
|
|
9
|
-
from .....llm.content import (
|
|
10
|
-
Audio,
|
|
11
|
-
Base64ImageSource,
|
|
12
|
-
Document,
|
|
13
|
-
Image,
|
|
14
|
-
Text,
|
|
15
|
-
Thought,
|
|
16
|
-
ToolCall,
|
|
17
|
-
ToolOutput,
|
|
18
|
-
)
|
|
19
|
-
from .....llm.content.document import Base64DocumentSource, TextDocumentSource
|
|
20
|
-
from .....llm.messages import AssistantMessage, Message, SystemMessage, UserMessage
|
|
21
|
-
from .....llm.responses.usage import Usage
|
|
22
|
-
from ...utils import json_dumps
|
|
23
|
-
from .cost import calculate_cost_async, calculate_cost_sync
|
|
24
|
-
|
|
25
|
-
if TYPE_CHECKING:
|
|
26
|
-
from opentelemetry.util.types import AttributeValue
|
|
27
|
-
|
|
28
|
-
from .....llm.responses.root_response import RootResponse
|
|
29
|
-
from .....llm.types import Jsonable
|
|
30
|
-
|
|
31
|
-
logger = logging.getLogger(__name__)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class SpanProtocol(Protocol):
|
|
35
|
-
"""Protocol for span objects that support setting attributes."""
|
|
36
|
-
|
|
37
|
-
def set(self, **attributes: AttributeValue) -> None:
|
|
38
|
-
"""Set attributes on the span."""
|
|
39
|
-
...
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _serialize_content_part(
|
|
43
|
-
part: Text | ToolCall | Thought | Image | Audio | Document | ToolOutput[Jsonable],
|
|
44
|
-
) -> dict[str, Any]:
|
|
45
|
-
"""Serialize a single content part to a dict matching the Mirascope dataclass structure."""
|
|
46
|
-
if isinstance(part, Text):
|
|
47
|
-
return {"type": "text", "text": part.text}
|
|
48
|
-
elif isinstance(part, ToolCall):
|
|
49
|
-
return {
|
|
50
|
-
"type": "tool_call",
|
|
51
|
-
"id": part.id,
|
|
52
|
-
"name": part.name,
|
|
53
|
-
"args": part.args,
|
|
54
|
-
}
|
|
55
|
-
elif isinstance(part, Thought):
|
|
56
|
-
return {"type": "thought", "thought": part.thought}
|
|
57
|
-
elif isinstance(part, ToolOutput):
|
|
58
|
-
return {
|
|
59
|
-
"type": "tool_output",
|
|
60
|
-
"id": part.id,
|
|
61
|
-
"name": part.name,
|
|
62
|
-
"result": part.result,
|
|
63
|
-
}
|
|
64
|
-
elif isinstance(part, Image):
|
|
65
|
-
if isinstance(part.source, Base64ImageSource):
|
|
66
|
-
return {
|
|
67
|
-
"type": "image",
|
|
68
|
-
"source": {
|
|
69
|
-
"type": "base64_image_source",
|
|
70
|
-
"mime_type": part.source.mime_type,
|
|
71
|
-
"data": part.source.data,
|
|
72
|
-
},
|
|
73
|
-
}
|
|
74
|
-
else: # URLImageSource
|
|
75
|
-
return {
|
|
76
|
-
"type": "image",
|
|
77
|
-
"source": {"type": "url_image_source", "url": part.source.url},
|
|
78
|
-
}
|
|
79
|
-
elif isinstance(part, Audio):
|
|
80
|
-
return {
|
|
81
|
-
"type": "audio",
|
|
82
|
-
"source": {
|
|
83
|
-
"type": "base64_audio_source",
|
|
84
|
-
"mime_type": part.source.mime_type,
|
|
85
|
-
"data": part.source.data,
|
|
86
|
-
},
|
|
87
|
-
}
|
|
88
|
-
elif isinstance(part, Document):
|
|
89
|
-
# Document has multiple source types - serialize based on actual type
|
|
90
|
-
if isinstance(part.source, Base64DocumentSource):
|
|
91
|
-
return {
|
|
92
|
-
"type": "document",
|
|
93
|
-
"source": {
|
|
94
|
-
"type": "base64_document_source",
|
|
95
|
-
"data": part.source.data,
|
|
96
|
-
"media_type": part.source.media_type,
|
|
97
|
-
},
|
|
98
|
-
}
|
|
99
|
-
elif isinstance(part.source, TextDocumentSource):
|
|
100
|
-
return {
|
|
101
|
-
"type": "document",
|
|
102
|
-
"source": {
|
|
103
|
-
"type": "text_document_source",
|
|
104
|
-
"data": part.source.data,
|
|
105
|
-
"media_type": part.source.media_type,
|
|
106
|
-
},
|
|
107
|
-
}
|
|
108
|
-
else: # URLDocumentSource
|
|
109
|
-
return {
|
|
110
|
-
"type": "document",
|
|
111
|
-
"source": {
|
|
112
|
-
"type": "url_document_source",
|
|
113
|
-
"url": part.source.url,
|
|
114
|
-
},
|
|
115
|
-
}
|
|
116
|
-
return {"type": "unknown"} # pragma: no cover
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def _serialize_message(message: Message) -> dict[str, Any]:
|
|
120
|
-
"""Serialize a Message to a dict matching the Mirascope dataclass structure."""
|
|
121
|
-
if isinstance(message, SystemMessage):
|
|
122
|
-
return {
|
|
123
|
-
"role": "system",
|
|
124
|
-
"content": _serialize_content_part(message.content),
|
|
125
|
-
}
|
|
126
|
-
elif isinstance(message, UserMessage):
|
|
127
|
-
return {
|
|
128
|
-
"role": "user",
|
|
129
|
-
"content": [_serialize_content_part(p) for p in message.content],
|
|
130
|
-
"name": message.name,
|
|
131
|
-
}
|
|
132
|
-
elif isinstance(message, AssistantMessage):
|
|
133
|
-
return {
|
|
134
|
-
"role": "assistant",
|
|
135
|
-
"content": [_serialize_content_part(p) for p in message.content],
|
|
136
|
-
"name": message.name,
|
|
137
|
-
}
|
|
138
|
-
return {"role": "unknown"} # pragma: no cover
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def serialize_mirascope_messages(messages: Sequence[Message]) -> str:
|
|
142
|
-
"""Serialize input messages to JSON for span attributes."""
|
|
143
|
-
return json_dumps([_serialize_message(m) for m in messages])
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def serialize_mirascope_content(
|
|
147
|
-
content: Sequence[Text | ToolCall | Thought],
|
|
148
|
-
) -> str:
|
|
149
|
-
"""Serialize response content to JSON for span attributes."""
|
|
150
|
-
return json_dumps([_serialize_content_part(p) for p in content])
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def serialize_mirascope_usage(usage: Usage | None) -> AttributeValue | None:
|
|
154
|
-
"""Serialize response usage to JSON for span attributes. Returns None if usage is None."""
|
|
155
|
-
if usage is None:
|
|
156
|
-
return None
|
|
157
|
-
return json_dumps(
|
|
158
|
-
{
|
|
159
|
-
"input_tokens": usage.input_tokens,
|
|
160
|
-
"output_tokens": usage.output_tokens,
|
|
161
|
-
"cache_read_tokens": usage.cache_read_tokens,
|
|
162
|
-
"cache_write_tokens": usage.cache_write_tokens,
|
|
163
|
-
"reasoning_tokens": usage.reasoning_tokens,
|
|
164
|
-
"total_tokens": usage.total_tokens,
|
|
165
|
-
}
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def serialize_mirascope_cost(
|
|
170
|
-
input_cost: float,
|
|
171
|
-
output_cost: float,
|
|
172
|
-
total_cost: float,
|
|
173
|
-
cache_read_cost: float | None = None,
|
|
174
|
-
cache_write_cost: float | None = None,
|
|
175
|
-
) -> str:
|
|
176
|
-
"""Serialize cost to JSON for span attributes.
|
|
177
|
-
|
|
178
|
-
All costs are in centicents (1 centicent = $0.0001).
|
|
179
|
-
Consumers can divide by 10,000 to get dollar amounts.
|
|
180
|
-
"""
|
|
181
|
-
return json_dumps(
|
|
182
|
-
{
|
|
183
|
-
"input_cost": input_cost,
|
|
184
|
-
"output_cost": output_cost,
|
|
185
|
-
"cache_read_cost": cache_read_cost,
|
|
186
|
-
"cache_write_cost": cache_write_cost,
|
|
187
|
-
"total_cost": total_cost,
|
|
188
|
-
}
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def attach_mirascope_response(
|
|
193
|
-
span: SpanProtocol, response: RootResponse[Any, Any]
|
|
194
|
-
) -> None:
|
|
195
|
-
"""Attach Mirascope-specific response attributes to a span.
|
|
196
|
-
|
|
197
|
-
Sets the following attributes:
|
|
198
|
-
- mirascope.trace.output: Pretty-printed response
|
|
199
|
-
- mirascope.response.messages: Serialized input messages (excluding final assistant message)
|
|
200
|
-
- mirascope.response.content: Serialized response content
|
|
201
|
-
- mirascope.response.usage: Serialized usage (if available)
|
|
202
|
-
- mirascope.response.cost: Serialized cost (if available)
|
|
203
|
-
"""
|
|
204
|
-
span.set(
|
|
205
|
-
**{
|
|
206
|
-
"mirascope.response.provider_id": response.provider_id,
|
|
207
|
-
"mirascope.response.model_id": response.model_id,
|
|
208
|
-
"mirascope.trace.output": response.pretty(),
|
|
209
|
-
"mirascope.response.messages": serialize_mirascope_messages(
|
|
210
|
-
response.messages[:-1]
|
|
211
|
-
),
|
|
212
|
-
"mirascope.response.content": serialize_mirascope_content(response.content),
|
|
213
|
-
}
|
|
214
|
-
)
|
|
215
|
-
if (usage_json := serialize_mirascope_usage(response.usage)) is not None:
|
|
216
|
-
span.set(**{"mirascope.response.usage": usage_json})
|
|
217
|
-
logger.debug("Attached usage to span")
|
|
218
|
-
else:
|
|
219
|
-
logger.debug("No usage available, skipping cost calculation")
|
|
220
|
-
|
|
221
|
-
# Calculate and attach cost if usage is available
|
|
222
|
-
if response.usage is not None:
|
|
223
|
-
logger.debug("Attempting cost calculation (sync)")
|
|
224
|
-
cost = calculate_cost_sync(
|
|
225
|
-
response.provider_id, response.model_id, response.usage
|
|
226
|
-
)
|
|
227
|
-
if cost is not None:
|
|
228
|
-
span.set(
|
|
229
|
-
**{
|
|
230
|
-
"mirascope.response.cost": serialize_mirascope_cost(
|
|
231
|
-
input_cost=cost.input_cost_centicents,
|
|
232
|
-
output_cost=cost.output_cost_centicents,
|
|
233
|
-
total_cost=cost.total_cost_centicents,
|
|
234
|
-
cache_read_cost=cost.cache_read_cost_centicents,
|
|
235
|
-
cache_write_cost=cost.cache_write_cost_centicents,
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
)
|
|
239
|
-
logger.debug(
|
|
240
|
-
"Attached cost to span: total=%s centicents", cost.total_cost_centicents
|
|
241
|
-
)
|
|
242
|
-
else:
|
|
243
|
-
logger.debug("Cost calculation returned None, not attaching cost to span")
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
async def attach_mirascope_response_async(
|
|
247
|
-
span: SpanProtocol, response: RootResponse[Any, Any]
|
|
248
|
-
) -> None:
|
|
249
|
-
"""Attach Mirascope-specific response attributes to a span (async version).
|
|
250
|
-
|
|
251
|
-
Sets the following attributes:
|
|
252
|
-
- mirascope.trace.output: Pretty-printed response
|
|
253
|
-
- mirascope.response.messages: Serialized input messages (excluding final assistant message)
|
|
254
|
-
- mirascope.response.content: Serialized response content
|
|
255
|
-
- mirascope.response.usage: Serialized usage (if available)
|
|
256
|
-
- mirascope.response.cost: Serialized cost (if available)
|
|
257
|
-
"""
|
|
258
|
-
span.set(
|
|
259
|
-
**{
|
|
260
|
-
"mirascope.response.provider_id": response.provider_id,
|
|
261
|
-
"mirascope.response.model_id": response.model_id,
|
|
262
|
-
"mirascope.trace.output": response.pretty(),
|
|
263
|
-
"mirascope.response.messages": serialize_mirascope_messages(
|
|
264
|
-
response.messages[:-1]
|
|
265
|
-
),
|
|
266
|
-
"mirascope.response.content": serialize_mirascope_content(response.content),
|
|
267
|
-
}
|
|
268
|
-
)
|
|
269
|
-
if (usage_json := serialize_mirascope_usage(response.usage)) is not None:
|
|
270
|
-
span.set(**{"mirascope.response.usage": usage_json})
|
|
271
|
-
logger.debug("Attached usage to span (async)")
|
|
272
|
-
else:
|
|
273
|
-
logger.debug("No usage available, skipping cost calculation (async)")
|
|
274
|
-
|
|
275
|
-
# Calculate and attach cost if usage is available (async)
|
|
276
|
-
if response.usage is not None:
|
|
277
|
-
logger.debug("Attempting cost calculation (async)")
|
|
278
|
-
cost = await calculate_cost_async(
|
|
279
|
-
response.provider_id, response.model_id, response.usage
|
|
280
|
-
)
|
|
281
|
-
if cost is not None:
|
|
282
|
-
span.set(
|
|
283
|
-
**{
|
|
284
|
-
"mirascope.response.cost": serialize_mirascope_cost(
|
|
285
|
-
input_cost=cost.input_cost_centicents,
|
|
286
|
-
output_cost=cost.output_cost_centicents,
|
|
287
|
-
total_cost=cost.total_cost_centicents,
|
|
288
|
-
cache_read_cost=cost.cache_read_cost_centicents,
|
|
289
|
-
cache_write_cost=cost.cache_write_cost_centicents,
|
|
290
|
-
)
|
|
291
|
-
}
|
|
292
|
-
)
|
|
293
|
-
logger.debug(
|
|
294
|
-
"Attached cost to span (async): total=%s centicents",
|
|
295
|
-
cost.total_cost_centicents,
|
|
296
|
-
)
|
|
297
|
-
else:
|
|
298
|
-
logger.debug(
|
|
299
|
-
"Cost calculation returned None, not attaching cost to span (async)"
|
|
300
|
-
)
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
"""Context propagation utilities for distributed tracing."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import logging
|
|
6
|
-
import os
|
|
7
|
-
from collections.abc import Mapping, MutableMapping
|
|
8
|
-
from typing import Literal, TypeAlias
|
|
9
|
-
|
|
10
|
-
from opentelemetry import propagate
|
|
11
|
-
from opentelemetry.context import Context
|
|
12
|
-
from opentelemetry.propagators.b3 import B3MultiFormat, B3SingleFormat
|
|
13
|
-
from opentelemetry.propagators.composite import CompositePropagator
|
|
14
|
-
from opentelemetry.propagators.jaeger import JaegerPropagator
|
|
15
|
-
from opentelemetry.propagators.textmap import Setter, TextMapPropagator
|
|
16
|
-
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
17
|
-
|
|
18
|
-
from ..exceptions import ConfigurationError
|
|
19
|
-
from .session import SESSION_HEADER_NAME, current_session
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
PropagatorFormat: TypeAlias = Literal[
|
|
24
|
-
"tracecontext", "b3", "b3multi", "jaeger", "composite"
|
|
25
|
-
]
|
|
26
|
-
CarrierValue: TypeAlias = str | list[str]
|
|
27
|
-
|
|
28
|
-
# Environment variable names
|
|
29
|
-
ENV_PROPAGATOR_FORMAT = "MIRASCOPE_PROPAGATOR"
|
|
30
|
-
ENV_PROPAGATOR_SET_GLOBAL = "_MIRASCOPE_PROPAGATOR_SET_GLOBAL"
|
|
31
|
-
|
|
32
|
-
_PROPAGATOR: ContextPropagator | None = None
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class _StrSetter(Setter[MutableMapping[str, str]]):
|
|
36
|
-
"""Setter that writes string header values into the carrier."""
|
|
37
|
-
|
|
38
|
-
def set(self, carrier: MutableMapping[str, str], key: str, value: str) -> None:
|
|
39
|
-
"""Set a single header value on the carrier."""
|
|
40
|
-
carrier[key] = value
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
_STR_SETTER = _StrSetter()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class ContextPropagator:
|
|
47
|
-
"""Manages OpenTelemetry context propagation across service boundaries."""
|
|
48
|
-
|
|
49
|
-
_propagator: TextMapPropagator
|
|
50
|
-
|
|
51
|
-
def __init__(self, *, set_global: bool = True) -> None:
|
|
52
|
-
"""Initialize propagator and optionally set as global.
|
|
53
|
-
|
|
54
|
-
Propagator format is determined by MIRASCOPE_PROPAGATOR environment variable.
|
|
55
|
-
Defaults to "tracecontext" if not set.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
set_global: Whether to set this propagator as the global textmap propagator.
|
|
59
|
-
|
|
60
|
-
Raises:
|
|
61
|
-
ConfigurationError: If the propagator format is invalid.
|
|
62
|
-
"""
|
|
63
|
-
env_format = os.environ.get(ENV_PROPAGATOR_FORMAT, "tracecontext")
|
|
64
|
-
propagator_name: PropagatorFormat
|
|
65
|
-
if env_format in ("tracecontext", "b3", "b3multi", "jaeger", "composite"):
|
|
66
|
-
propagator_name = env_format
|
|
67
|
-
else:
|
|
68
|
-
error_message = (
|
|
69
|
-
f"Invalid propagator format: {env_format}. "
|
|
70
|
-
f"Valid options: tracecontext, b3, b3multi, jaeger, composite"
|
|
71
|
-
)
|
|
72
|
-
logger.error(error_message)
|
|
73
|
-
raise ConfigurationError(error_message)
|
|
74
|
-
logger.debug(f"Initializing ContextPropagator with format: {propagator_name}")
|
|
75
|
-
|
|
76
|
-
match propagator_name:
|
|
77
|
-
case "tracecontext":
|
|
78
|
-
self._propagator = TraceContextTextMapPropagator()
|
|
79
|
-
case "b3":
|
|
80
|
-
self._propagator = B3SingleFormat()
|
|
81
|
-
case "b3multi":
|
|
82
|
-
self._propagator = B3MultiFormat()
|
|
83
|
-
case "jaeger":
|
|
84
|
-
self._propagator = JaegerPropagator()
|
|
85
|
-
case "composite":
|
|
86
|
-
propagators: list[TextMapPropagator] = [
|
|
87
|
-
TraceContextTextMapPropagator(),
|
|
88
|
-
B3SingleFormat(),
|
|
89
|
-
B3MultiFormat(),
|
|
90
|
-
JaegerPropagator(),
|
|
91
|
-
]
|
|
92
|
-
self._propagator = CompositePropagator(propagators)
|
|
93
|
-
|
|
94
|
-
if set_global:
|
|
95
|
-
should_set_global = os.environ.get(ENV_PROPAGATOR_SET_GLOBAL, "true")
|
|
96
|
-
if should_set_global.lower() == "true":
|
|
97
|
-
propagate.set_global_textmap(self._propagator)
|
|
98
|
-
logger.debug(f"Set {propagator_name} as global textmap propagator")
|
|
99
|
-
|
|
100
|
-
def extract_context(self, carrier: Mapping[str, CarrierValue]) -> Context:
|
|
101
|
-
"""Extract OTEL context from carrier headers.
|
|
102
|
-
|
|
103
|
-
Args:
|
|
104
|
-
carrier: Dictionary containing HTTP headers or similar carrier data.
|
|
105
|
-
|
|
106
|
-
Returns:
|
|
107
|
-
Extracted OpenTelemetry context. Returns empty context if extraction fails.
|
|
108
|
-
"""
|
|
109
|
-
try:
|
|
110
|
-
context = self._propagator.extract(carrier=carrier)
|
|
111
|
-
logger.debug("Successfully extracted context from carrier")
|
|
112
|
-
return context
|
|
113
|
-
except Exception as exception:
|
|
114
|
-
logger.debug(
|
|
115
|
-
f"Failed to extract context from carrier: {type(exception).__name__}: {exception}"
|
|
116
|
-
)
|
|
117
|
-
return Context()
|
|
118
|
-
|
|
119
|
-
def inject_context(
|
|
120
|
-
self,
|
|
121
|
-
carrier: MutableMapping[str, str],
|
|
122
|
-
context: Context | None = None,
|
|
123
|
-
) -> None:
|
|
124
|
-
"""Inject current OTEL context into carrier headers.
|
|
125
|
-
|
|
126
|
-
This method also injects session context if one is active, adding the
|
|
127
|
-
SESSION_HEADER_NAME header to the carrier.
|
|
128
|
-
|
|
129
|
-
Args:
|
|
130
|
-
carrier: Mutable mapping (e.g., HTTP headers dict) to inject context into.
|
|
131
|
-
context: Optional specific context to inject. If None, uses current context.
|
|
132
|
-
"""
|
|
133
|
-
try:
|
|
134
|
-
self._propagator.inject(
|
|
135
|
-
carrier=carrier, context=context, setter=_STR_SETTER
|
|
136
|
-
)
|
|
137
|
-
logger.debug("Successfully injected context into carrier")
|
|
138
|
-
except Exception as exception:
|
|
139
|
-
logger.debug(
|
|
140
|
-
f"Failed to inject context into carrier: {type(exception).__name__}: {exception}"
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
session_ctx = current_session()
|
|
144
|
-
if session_ctx is not None:
|
|
145
|
-
carrier[SESSION_HEADER_NAME] = session_ctx.id
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
def get_propagator() -> ContextPropagator:
|
|
149
|
-
"""Get or create the singleton ContextPropagator instance.
|
|
150
|
-
|
|
151
|
-
Reads propagator format from MIRASCOPE_PROPAGATOR environment variable.
|
|
152
|
-
|
|
153
|
-
Returns:
|
|
154
|
-
The global ContextPropagator instance.
|
|
155
|
-
"""
|
|
156
|
-
global _PROPAGATOR
|
|
157
|
-
if _PROPAGATOR is None:
|
|
158
|
-
_PROPAGATOR = ContextPropagator()
|
|
159
|
-
return _PROPAGATOR
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def reset_propagator() -> None:
|
|
163
|
-
"""Reset the singleton ContextPropagator instance.
|
|
164
|
-
|
|
165
|
-
This is primarily useful for testing to ensure a clean state between tests.
|
|
166
|
-
The next call to get_propagator() will create a new instance.
|
|
167
|
-
"""
|
|
168
|
-
global _PROPAGATOR
|
|
169
|
-
_PROPAGATOR = None
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def extract_context(carrier: Mapping[str, CarrierValue]) -> Context:
|
|
173
|
-
"""Extract OTEL context from carrier headers using the global propagator.
|
|
174
|
-
|
|
175
|
-
Args:
|
|
176
|
-
carrier: Dictionary containing HTTP headers or similar carrier data.
|
|
177
|
-
|
|
178
|
-
Returns:
|
|
179
|
-
Extracted OpenTelemetry context.
|
|
180
|
-
"""
|
|
181
|
-
return get_propagator().extract_context(carrier)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
def inject_context(
|
|
185
|
-
carrier: MutableMapping[str, str],
|
|
186
|
-
*,
|
|
187
|
-
context: Context | None = None,
|
|
188
|
-
) -> None:
|
|
189
|
-
"""Inject current OTEL context into carrier headers using the global propagator.
|
|
190
|
-
|
|
191
|
-
This function also injects session context if one is active, adding the
|
|
192
|
-
SESSION_HEADER_NAME header to the carrier.
|
|
193
|
-
|
|
194
|
-
Args:
|
|
195
|
-
carrier: Mutable mapping (e.g., HTTP headers dict) to inject context into.
|
|
196
|
-
context: Optional specific context to inject. If None, uses current context.
|
|
197
|
-
"""
|
|
198
|
-
get_propagator().inject_context(carrier, context)
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"""Call protocol helpers for ops.tracing."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import inspect
|
|
6
|
-
from typing import TYPE_CHECKING, Protocol
|
|
7
|
-
from typing_extensions import TypeIs
|
|
8
|
-
|
|
9
|
-
from ...llm.context import Context, DepsT
|
|
10
|
-
from .types import P, R
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from .spans import Span
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class SyncFunction(Protocol[P, R]):
|
|
17
|
-
"""Protocol for synchronous callable functions."""
|
|
18
|
-
|
|
19
|
-
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
20
|
-
"""The function required a synchronous call method."""
|
|
21
|
-
... # pragma: no cover
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class AsyncFunction(Protocol[P, R]):
|
|
25
|
-
"""Protocol for asynchronous callable functions."""
|
|
26
|
-
|
|
27
|
-
async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
28
|
-
"""The function's required asynchronous call method."""
|
|
29
|
-
... # pragma: no cover
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class SyncSpanFunction(Protocol[P, R]):
|
|
33
|
-
"""Protocol for synchronous functions that receive injected Span.
|
|
34
|
-
|
|
35
|
-
Functions matching this protocol have `trace_ctx: Span` as their first
|
|
36
|
-
parameter. The trace decorator will inject the span automatically.
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
def __call__(self, trace_ctx: Span, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
40
|
-
"""The function receives a Span as first parameter."""
|
|
41
|
-
... # pragma: no cover
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class AsyncSpanFunction(Protocol[P, R]):
|
|
45
|
-
"""Protocol for asynchronous functions that receive injected Span.
|
|
46
|
-
|
|
47
|
-
Functions matching this protocol have `trace_ctx: Span` as their first
|
|
48
|
-
parameter. The trace decorator will inject the span automatically.
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
async def __call__(self, trace_ctx: Span, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
52
|
-
"""The function receives a Span as first parameter."""
|
|
53
|
-
... # pragma: no cover
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class SyncContextFunction(Protocol[P, DepsT, R]):
|
|
57
|
-
"""Protocol for synchronous callable functions with Context parameter."""
|
|
58
|
-
|
|
59
|
-
def __call__(self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs) -> R:
|
|
60
|
-
"""The function required a synchronous call method with context."""
|
|
61
|
-
... # pragma: no cover
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class AsyncContextFunction(Protocol[P, DepsT, R]):
|
|
65
|
-
"""Protocol for asynchronous callable functions with Context parameter."""
|
|
66
|
-
|
|
67
|
-
async def __call__(
|
|
68
|
-
self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
|
|
69
|
-
) -> R:
|
|
70
|
-
"""The function's required asynchronous call method with context."""
|
|
71
|
-
... # pragma: no cover
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def fn_is_async(
|
|
75
|
-
fn: SyncFunction[P, R] | AsyncFunction[P, R],
|
|
76
|
-
) -> TypeIs[AsyncFunction[P, R]]:
|
|
77
|
-
"""Type check to determine if a given function is asynchronous."""
|
|
78
|
-
return inspect.iscoroutinefunction(fn) or inspect.isasyncgenfunction(fn)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def fn_wants_span(
|
|
82
|
-
fn: (
|
|
83
|
-
SyncFunction[P, R]
|
|
84
|
-
| AsyncFunction[P, R]
|
|
85
|
-
| SyncSpanFunction[P, R]
|
|
86
|
-
| AsyncSpanFunction[P, R]
|
|
87
|
-
),
|
|
88
|
-
) -> TypeIs[SyncSpanFunction[P, R] | AsyncSpanFunction[P, R]]:
|
|
89
|
-
"""Check if function wants Span injection as first parameter.
|
|
90
|
-
|
|
91
|
-
Returns True if the function has a first parameter named `trace_ctx`
|
|
92
|
-
with type annotation `Span`.
|
|
93
|
-
"""
|
|
94
|
-
# Import here to avoid circular imports
|
|
95
|
-
from .spans import Span
|
|
96
|
-
|
|
97
|
-
try:
|
|
98
|
-
sig = inspect.signature(fn)
|
|
99
|
-
except (ValueError, TypeError):
|
|
100
|
-
return False
|
|
101
|
-
|
|
102
|
-
params = list(sig.parameters.values())
|
|
103
|
-
if not params:
|
|
104
|
-
return False
|
|
105
|
-
|
|
106
|
-
first_param = params[0]
|
|
107
|
-
if first_param.name != "trace_ctx":
|
|
108
|
-
return False
|
|
109
|
-
|
|
110
|
-
# Check annotation
|
|
111
|
-
annotation = first_param.annotation
|
|
112
|
-
if annotation is inspect.Parameter.empty:
|
|
113
|
-
return False
|
|
114
|
-
|
|
115
|
-
# Handle string annotations (forward references)
|
|
116
|
-
# The annotation could be "Span", "ops.Span", "mirascope.ops.Span", etc.
|
|
117
|
-
if isinstance(annotation, str):
|
|
118
|
-
return annotation == "Span" or annotation.endswith(".Span")
|
|
119
|
-
|
|
120
|
-
# Check by identity first
|
|
121
|
-
if annotation is Span:
|
|
122
|
-
return True
|
|
123
|
-
|
|
124
|
-
# Fallback: check by class name and module for robustness
|
|
125
|
-
# This handles cases where the same class might have different identities
|
|
126
|
-
# due to module reloading or import issues in test environments
|
|
127
|
-
if isinstance(annotation, type):
|
|
128
|
-
return (
|
|
129
|
-
annotation.__name__ == "Span"
|
|
130
|
-
and annotation.__module__ == "mirascope.ops._internal.spans"
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
return False
|