mirascope 1.25.7__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 +3 -59
- mirascope/graphs/__init__.py +22 -0
- mirascope/{experimental/graphs → graphs}/finite_state_machine.py +70 -159
- mirascope/llm/__init__.py +206 -16
- 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 +16 -0
- mirascope/llm/calls/base_call.py +33 -0
- mirascope/llm/calls/calls.py +315 -0
- mirascope/llm/calls/decorator.py +255 -0
- mirascope/llm/clients/__init__.py +34 -0
- mirascope/llm/clients/anthropic/__init__.py +11 -0
- mirascope/llm/clients/anthropic/_utils/__init__.py +13 -0
- mirascope/llm/clients/anthropic/_utils/decode.py +244 -0
- 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/clients/base/__init__.py +15 -0
- mirascope/llm/clients/base/_utils.py +192 -0
- mirascope/llm/clients/base/client.py +1256 -0
- mirascope/llm/clients/base/kwargs.py +12 -0
- mirascope/llm/clients/base/params.py +93 -0
- mirascope/llm/clients/google/__init__.py +6 -0
- mirascope/llm/clients/google/_utils/__init__.py +13 -0
- mirascope/llm/clients/google/_utils/decode.py +231 -0
- mirascope/llm/clients/google/_utils/encode.py +279 -0
- mirascope/llm/clients/google/clients.py +853 -0
- mirascope/llm/clients/google/message.py +7 -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/clients/openai/completions/_utils/__init__.py +13 -0
- mirascope/llm/clients/openai/completions/_utils/decode.py +187 -0
- mirascope/llm/clients/openai/completions/_utils/encode.py +358 -0
- 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/clients/openai/responses/_utils/decode.py +194 -0
- mirascope/llm/clients/openai/responses/_utils/encode.py +333 -0
- 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 +70 -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 +63 -0
- mirascope/llm/content/tool_output.py +26 -0
- mirascope/llm/context/__init__.py +6 -0
- mirascope/llm/context/_utils.py +28 -0
- mirascope/llm/context/context.py +24 -0
- mirascope/llm/exceptions.py +105 -0
- mirascope/llm/formatting/__init__.py +22 -0
- mirascope/llm/formatting/_utils.py +74 -0
- mirascope/llm/formatting/format.py +104 -0
- mirascope/llm/formatting/from_call_args.py +30 -0
- mirascope/llm/formatting/partial.py +58 -0
- mirascope/llm/formatting/types.py +109 -0
- mirascope/llm/mcp/__init__.py +5 -0
- mirascope/llm/mcp/client.py +118 -0
- mirascope/llm/messages/__init__.py +32 -0
- mirascope/llm/messages/message.py +182 -0
- mirascope/llm/models/__init__.py +16 -0
- mirascope/llm/models/models.py +1243 -0
- mirascope/llm/prompts/__init__.py +33 -0
- mirascope/llm/prompts/_utils.py +60 -0
- mirascope/llm/prompts/decorator.py +286 -0
- mirascope/llm/prompts/protocols.py +99 -0
- mirascope/llm/responses/__init__.py +57 -0
- mirascope/llm/responses/_utils.py +56 -0
- mirascope/llm/responses/base_response.py +91 -0
- mirascope/llm/responses/base_stream_response.py +697 -0
- mirascope/llm/responses/finish_reason.py +27 -0
- mirascope/llm/responses/response.py +345 -0
- mirascope/llm/responses/root_response.py +177 -0
- mirascope/llm/responses/stream_response.py +572 -0
- mirascope/llm/responses/streams.py +363 -0
- mirascope/llm/tools/__init__.py +40 -0
- mirascope/llm/tools/_utils.py +25 -0
- mirascope/llm/tools/decorator.py +175 -0
- mirascope/llm/tools/protocols.py +96 -0
- mirascope/llm/tools/tool_schema.py +246 -0
- mirascope/llm/tools/toolkit.py +152 -0
- mirascope/llm/tools/tools.py +169 -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-2.0.0a0.dist-info/METADATA +117 -0
- mirascope-2.0.0a0.dist-info/RECORD +101 -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 -62
- mirascope/beta/rag/chroma/vectorstores.py +0 -121
- 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 -109
- 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/_thinking.py +0 -70
- 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 -154
- mirascope/core/anthropic/_utils/_setup_call.py +0 -146
- mirascope/core/anthropic/call_params.py +0 -44
- mirascope/core/anthropic/call_response.py +0 -226
- mirascope/core/anthropic/call_response_chunk.py +0 -152
- mirascope/core/anthropic/dynamic_config.py +0 -40
- mirascope/core/anthropic/py.typed +0 -0
- mirascope/core/anthropic/stream.py +0 -204
- 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 -86
- 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 -178
- 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 -24
- 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 -323
- 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 -338
- 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 -175
- mirascope/core/base/messages.py +0 -116
- 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 -214
- 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 -172
- mirascope/core/bedrock/_utils/_setup_call.py +0 -258
- mirascope/core/bedrock/call_params.py +0 -38
- mirascope/core/bedrock/call_response.py +0 -248
- 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 -100
- 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 -297
- mirascope/core/google/_utils/_get_json_output.py +0 -37
- mirascope/core/google/_utils/_handle_stream.py +0 -58
- mirascope/core/google/_utils/_message_param_converter.py +0 -200
- mirascope/core/google/_utils/_setup_call.py +0 -201
- mirascope/core/google/_utils/_validate_media_type.py +0 -58
- mirascope/core/google/call_params.py +0 -22
- mirascope/core/google/call_response.py +0 -255
- mirascope/core/google/call_response_chunk.py +0 -135
- mirascope/core/google/dynamic_config.py +0 -26
- mirascope/core/google/stream.py +0 -199
- 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 -164
- 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 -81
- 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 -148
- 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 -92
- 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/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 -158
- 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 -288
- 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 -131
- 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.25.7.dist-info/METADATA +0 -169
- mirascope-1.25.7.dist-info/RECORD +0 -378
- {mirascope-1.25.7.dist-info → mirascope-2.0.0a0.dist-info}/WHEEL +0 -0
- {mirascope-1.25.7.dist-info → mirascope-2.0.0a0.dist-info}/licenses/LICENSE +0 -0
mirascope/retries/fallback.py
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
"""The `fallback` module provides a fallback retry strategy."""
|
|
2
|
-
|
|
3
|
-
import inspect
|
|
4
|
-
from collections.abc import Callable, Coroutine
|
|
5
|
-
from typing import Any, ParamSpec, Protocol, TypeVar, overload
|
|
6
|
-
|
|
7
|
-
from pydantic import BaseModel
|
|
8
|
-
from typing_extensions import NotRequired, Required, TypedDict
|
|
9
|
-
|
|
10
|
-
from .. import llm
|
|
11
|
-
from ..core.base import CommonCallParams
|
|
12
|
-
from ..core.base.types import Provider
|
|
13
|
-
|
|
14
|
-
_P = ParamSpec("_P")
|
|
15
|
-
_R = TypeVar("_R")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class FallbackDecorator(Protocol):
|
|
19
|
-
@overload
|
|
20
|
-
def __call__(
|
|
21
|
-
self, fn: Callable[_P, Coroutine[_R, Any, Any]]
|
|
22
|
-
) -> Callable[_P, Coroutine[_R, Any, Any]]: ...
|
|
23
|
-
|
|
24
|
-
@overload
|
|
25
|
-
def __call__(self, fn: Callable[_P, _R]) -> Callable[_P, _R]: ...
|
|
26
|
-
|
|
27
|
-
def __call__(
|
|
28
|
-
self,
|
|
29
|
-
fn: Callable[_P, _R] | Callable[_P, Coroutine[_R, Any, Any]],
|
|
30
|
-
) -> Callable[_P, _R] | Callable[_P, Coroutine[_R, Any, Any]]: ...
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class Fallback(TypedDict):
|
|
34
|
-
"""The override arguments to use for this fallback attempt."""
|
|
35
|
-
|
|
36
|
-
catch: Required[type[Exception] | tuple[type[Exception]]]
|
|
37
|
-
provider: Required[Provider]
|
|
38
|
-
model: Required[str]
|
|
39
|
-
call_params: NotRequired[CommonCallParams]
|
|
40
|
-
client: NotRequired[Any]
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class FallbackError(Exception):
|
|
44
|
-
"""An error raised when all fallbacks fail."""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def fallback(
|
|
48
|
-
catch: type[Exception] | tuple[type[Exception]],
|
|
49
|
-
fallbacks: list[Fallback],
|
|
50
|
-
) -> FallbackDecorator:
|
|
51
|
-
"""A decorator that retries the function call with a fallback strategy.
|
|
52
|
-
|
|
53
|
-
This must use the provider-agnostic `llm.call` decorator.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
catch: The exception(s) to catch for the original call.
|
|
57
|
-
backups: The list of backup providers to try in order. Each backup provider
|
|
58
|
-
is a tuple of the provider name, the model name, and the call params.
|
|
59
|
-
The call params may be `None` if no change is wanted.
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
The decorated function.
|
|
63
|
-
|
|
64
|
-
Raises:
|
|
65
|
-
FallbackError: If all fallbacks fail.
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
@overload
|
|
69
|
-
def decorator(
|
|
70
|
-
fn: Callable[_P, Coroutine[_R, Any, Any]],
|
|
71
|
-
) -> Callable[_P, Coroutine[_R, Any, Any]]: ...
|
|
72
|
-
|
|
73
|
-
@overload
|
|
74
|
-
def decorator(fn: Callable[_P, _R]) -> Callable[_P, _R]: ...
|
|
75
|
-
|
|
76
|
-
def decorator(
|
|
77
|
-
fn: Callable[_P, _R] | Callable[_P, Coroutine[_R, Any, Any]],
|
|
78
|
-
) -> Callable[_P, _R] | Callable[_P, Coroutine[_R, Any, Any]]:
|
|
79
|
-
fn_to_check = fn._original_fn if hasattr(fn, "_original_fn") else fn # pyright: ignore [reportFunctionMemberAccess]
|
|
80
|
-
if inspect.iscoroutinefunction(fn_to_check):
|
|
81
|
-
|
|
82
|
-
async def inner_async(*args: _P.args, **kwargs: _P.kwargs) -> _R:
|
|
83
|
-
caught: list[Exception] = []
|
|
84
|
-
try:
|
|
85
|
-
return await fn(*args, **kwargs) # pyright: ignore [reportReturnType,reportGeneralTypeIssues]
|
|
86
|
-
except catch as e:
|
|
87
|
-
caught.append(e)
|
|
88
|
-
for backup in fallbacks:
|
|
89
|
-
try:
|
|
90
|
-
with llm.context(
|
|
91
|
-
provider=backup["provider"],
|
|
92
|
-
model=backup["model"],
|
|
93
|
-
call_params=backup.get("call_params", None),
|
|
94
|
-
client=backup.get("client", None),
|
|
95
|
-
):
|
|
96
|
-
response = await fn(*args, **kwargs) # pyright: ignore [reportGeneralTypeIssues]
|
|
97
|
-
if isinstance(response, BaseModel):
|
|
98
|
-
response._caught = caught # pyright: ignore [reportAttributeAccessIssue]
|
|
99
|
-
return response # pyright: ignore [reportReturnType]
|
|
100
|
-
except backup["catch"] as be:
|
|
101
|
-
caught.append(be)
|
|
102
|
-
raise FallbackError(f"All fallbacks failed:\n{caught}")
|
|
103
|
-
|
|
104
|
-
return inner_async
|
|
105
|
-
else:
|
|
106
|
-
|
|
107
|
-
def inner(*args: _P.args, **kwargs: _P.kwargs) -> _R:
|
|
108
|
-
caught: list[Exception] = []
|
|
109
|
-
try:
|
|
110
|
-
return fn(*args, **kwargs) # pyright: ignore [reportReturnType]
|
|
111
|
-
except catch as e:
|
|
112
|
-
caught.append(e)
|
|
113
|
-
for backup in fallbacks:
|
|
114
|
-
try:
|
|
115
|
-
with llm.context(
|
|
116
|
-
provider=backup["provider"],
|
|
117
|
-
model=backup["model"],
|
|
118
|
-
call_params=backup.get("call_params", None),
|
|
119
|
-
client=backup.get("client", None),
|
|
120
|
-
):
|
|
121
|
-
response = fn(*args, **kwargs)
|
|
122
|
-
if isinstance(response, BaseModel):
|
|
123
|
-
response._caught = caught # pyright: ignore [reportAttributeAccessIssue]
|
|
124
|
-
return response # pyright: ignore [reportReturnType]
|
|
125
|
-
except backup["catch"] as be:
|
|
126
|
-
caught.append(be)
|
|
127
|
-
raise FallbackError(f"All fallbacks failed:\n{caught}")
|
|
128
|
-
|
|
129
|
-
return inner
|
|
130
|
-
|
|
131
|
-
return decorator
|
mirascope/retries/tenacity.py
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"""Utitlies for more easily using Tenacity to reinsert errors on failed API calls."""
|
|
2
|
-
|
|
3
|
-
from collections.abc import Callable
|
|
4
|
-
|
|
5
|
-
from tenacity import RetryCallState
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def collect_errors(
|
|
9
|
-
*args: type[Exception],
|
|
10
|
-
) -> Callable[[RetryCallState], None]:
|
|
11
|
-
"""Collects specified errors into an `errors` keyword argument.
|
|
12
|
-
|
|
13
|
-
Example:
|
|
14
|
-
|
|
15
|
-
```python
|
|
16
|
-
from mirascope.integrations.tenacity import collect_errors
|
|
17
|
-
from tenacity import retry, stop_after_attempt
|
|
18
|
-
|
|
19
|
-
@retry(stop=stop_after_attempt(3), after=collect_errors(ValueError))
|
|
20
|
-
def throw_value_error(*, errors: list[ValueError] | None = None):
|
|
21
|
-
if errors:
|
|
22
|
-
print(errors[-1])
|
|
23
|
-
raise ValueError("Throwing Error")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
try:
|
|
27
|
-
throw_value_error()
|
|
28
|
-
# > Throwing Error
|
|
29
|
-
# > Throwing Error
|
|
30
|
-
except RetryError:
|
|
31
|
-
...
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
*args: The `Exception` types to catch.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
def inner(retry_state: RetryCallState) -> None:
|
|
39
|
-
"""Collect errors into a `errors` kwarg of the wrapped function."""
|
|
40
|
-
if (
|
|
41
|
-
(outcome := retry_state.outcome)
|
|
42
|
-
and (exception := outcome.exception())
|
|
43
|
-
and type(exception) in args
|
|
44
|
-
):
|
|
45
|
-
errors = retry_state.kwargs.pop("errors", [])
|
|
46
|
-
retry_state.kwargs["errors"] = (
|
|
47
|
-
errors + [exception] if errors else [exception]
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
return inner
|
mirascope/tools/__init__.py
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from contextlib import suppress
|
|
2
|
-
|
|
3
|
-
from .system._file_system import FileSystemToolKit, FileSystemToolKitConfig
|
|
4
|
-
|
|
5
|
-
with suppress(ImportError):
|
|
6
|
-
from .system._docker_operation import (
|
|
7
|
-
DockerOperationToolKit,
|
|
8
|
-
DockerOperationToolKitConfig,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
with suppress(ImportError):
|
|
12
|
-
from .web._duckduckgo import DuckDuckGoSearch, DuckDuckGoSearchConfig
|
|
13
|
-
|
|
14
|
-
with suppress(ImportError):
|
|
15
|
-
from .web._httpx import HTTPX, AsyncHTTPX, HTTPXConfig
|
|
16
|
-
|
|
17
|
-
with suppress(ImportError):
|
|
18
|
-
from .web._parse_url_content import ParseURLConfig, ParseURLContent
|
|
19
|
-
|
|
20
|
-
with suppress(ImportError):
|
|
21
|
-
from .web._requests import Requests, RequestsConfig
|
|
22
|
-
|
|
23
|
-
__all__ = [
|
|
24
|
-
"HTTPX",
|
|
25
|
-
"AsyncHTTPX",
|
|
26
|
-
"DockerOperationToolKit",
|
|
27
|
-
"DockerOperationToolKitConfig",
|
|
28
|
-
"DuckDuckGoSearch",
|
|
29
|
-
"DuckDuckGoSearchConfig",
|
|
30
|
-
"FileSystemToolKit",
|
|
31
|
-
"FileSystemToolKitConfig",
|
|
32
|
-
"HTTPXConfig",
|
|
33
|
-
"ParseURLConfig",
|
|
34
|
-
"ParseURLContent",
|
|
35
|
-
"Requests",
|
|
36
|
-
"RequestsConfig",
|
|
37
|
-
]
|
mirascope/tools/base.py
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import inspect
|
|
4
|
-
from abc import ABC
|
|
5
|
-
from typing import ClassVar, Generic, TypeVar, cast
|
|
6
|
-
|
|
7
|
-
from pydantic import BaseModel, ConfigDict, create_model
|
|
8
|
-
|
|
9
|
-
from mirascope.core import BaseTool, BaseToolKit
|
|
10
|
-
from mirascope.core.base._utils import DEFAULT_TOOL_DOCSTRING
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class _ConfigurableToolConfig(BaseModel, ABC):
|
|
14
|
-
"""Base configuration for tools"""
|
|
15
|
-
|
|
16
|
-
@classmethod
|
|
17
|
-
def from_env(cls: type[_ConfigurableToolConfigT]) -> _ConfigurableToolConfigT:
|
|
18
|
-
"""Returns a configuration instance from environment variables."""
|
|
19
|
-
return cls()
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
_ConfigurableToolConfigT = TypeVar(
|
|
23
|
-
"_ConfigurableToolConfigT", bound=_ConfigurableToolConfig
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
_ToolSchemaT = TypeVar("_ToolSchemaT")
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class ConfigurableTool(BaseTool, Generic[_ConfigurableToolConfigT], ABC):
|
|
30
|
-
"""Abstract base class for configurable tools.
|
|
31
|
-
|
|
32
|
-
Subclasses must define a `__prompt_usage_description__` class variable
|
|
33
|
-
and __configurable_tool_config__ class variable with a subclass of _ToolConfig.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
__configurable_tool_config__: ClassVar[_ConfigurableToolConfig]
|
|
37
|
-
__prompt_usage_description__: ClassVar[str]
|
|
38
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
39
|
-
|
|
40
|
-
@classmethod
|
|
41
|
-
def _get_config(cls) -> _ConfigurableToolConfigT:
|
|
42
|
-
"""Get tool configuration"""
|
|
43
|
-
return cast(_ConfigurableToolConfigT, cls.__configurable_tool_config__)
|
|
44
|
-
|
|
45
|
-
@classmethod
|
|
46
|
-
def from_config(
|
|
47
|
-
cls: type[_ConfigurableToolT], config: _ConfigurableToolConfigT
|
|
48
|
-
) -> type[_ConfigurableToolT]:
|
|
49
|
-
"""Create tool class with custom configuration"""
|
|
50
|
-
|
|
51
|
-
# ClassVar cannot get TypeVar Type. So, we need the comment to ignore the error.
|
|
52
|
-
config = cls._get_config().model_validate(config) # pyright: ignore [reportAssignmentType]
|
|
53
|
-
new_model = create_model(
|
|
54
|
-
cls.__name__,
|
|
55
|
-
__base__=cls,
|
|
56
|
-
__module__=cls.__module__,
|
|
57
|
-
__doc__=cls.__doc__ if cls.__doc__ else DEFAULT_TOOL_DOCSTRING,
|
|
58
|
-
)
|
|
59
|
-
new_model.__prompt_usage_description__ = cls.__prompt_usage_description__
|
|
60
|
-
new_model.__configurable_tool_config__ = config
|
|
61
|
-
return new_model
|
|
62
|
-
|
|
63
|
-
@classmethod
|
|
64
|
-
def usage_description(cls) -> str:
|
|
65
|
-
"""Returns instructions for using this tool."""
|
|
66
|
-
return inspect.cleandoc(cls.__prompt_usage_description__)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
_ConfigurableToolT = TypeVar("_ConfigurableToolT", bound=ConfigurableTool)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class ConfigurableToolKit(BaseToolKit, Generic[_ConfigurableToolConfigT], ABC):
|
|
73
|
-
"""Abstract base class for configurable toolkit.
|
|
74
|
-
|
|
75
|
-
Subclasses must define a `__prompt_usage_description__` class variable
|
|
76
|
-
and __config__ class variable with a subclass of _ToolConfig.
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
config: _ConfigurableToolConfigT
|
|
80
|
-
__prompt_usage_description__: ClassVar[str]
|
|
81
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
82
|
-
|
|
83
|
-
def create_tools(self) -> list[type[BaseTool]]:
|
|
84
|
-
"""The method to create the tools."""
|
|
85
|
-
return [
|
|
86
|
-
tool.from_config(self.config)
|
|
87
|
-
if issubclass(tool, ConfigurableTool) and "config" in self.model_fields_set
|
|
88
|
-
else tool
|
|
89
|
-
for tool in super().create_tools()
|
|
90
|
-
]
|
|
91
|
-
|
|
92
|
-
@classmethod
|
|
93
|
-
def usage_description(cls) -> str:
|
|
94
|
-
"""Returns instructions for using this toolkit."""
|
|
95
|
-
return inspect.cleandoc(cls.__prompt_usage_description__)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
_ConfigurableToolKitT = TypeVar("_ConfigurableToolKitT", bound=ConfigurableToolKit)
|
|
File without changes
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import io
|
|
4
|
-
import tarfile
|
|
5
|
-
from abc import ABC
|
|
6
|
-
from contextlib import suppress
|
|
7
|
-
from typing import ClassVar
|
|
8
|
-
|
|
9
|
-
import docker
|
|
10
|
-
from docker.models.containers import Container
|
|
11
|
-
from pydantic import BaseModel, Field
|
|
12
|
-
|
|
13
|
-
from mirascope.core import BaseTool, toolkit_tool
|
|
14
|
-
from mirascope.tools.base import (
|
|
15
|
-
ConfigurableTool,
|
|
16
|
-
ConfigurableToolKit,
|
|
17
|
-
_ConfigurableToolConfig,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class DockerOperationToolKitConfig(_ConfigurableToolConfig):
|
|
22
|
-
"""Configuration for `DockerOperationToolKit` toolkit"""
|
|
23
|
-
|
|
24
|
-
docker_image: str = Field(
|
|
25
|
-
default="python:3.13-slim", description="Docker image for code execution"
|
|
26
|
-
)
|
|
27
|
-
max_memory: str = Field(default="512m", description="Maximum memory allocation")
|
|
28
|
-
allow_network: bool = Field(default=True, description="Allow network access")
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class DockerOperation(ConfigurableTool[DockerOperationToolKitConfig], ABC):
|
|
32
|
-
"""Base class for Docker operations."""
|
|
33
|
-
|
|
34
|
-
__configurable_tool_config__ = DockerOperationToolKitConfig()
|
|
35
|
-
_docker_container: DockerContainer
|
|
36
|
-
|
|
37
|
-
@classmethod
|
|
38
|
-
def _create_tar_stream(cls, files: dict[str, str]) -> io.BytesIO:
|
|
39
|
-
"""Creates a tar stream from a dictionary of files."""
|
|
40
|
-
stream = io.BytesIO()
|
|
41
|
-
with tarfile.open(fileobj=stream, mode="w") as tar:
|
|
42
|
-
for name, content in files.items():
|
|
43
|
-
info = tarfile.TarInfo(name=name)
|
|
44
|
-
encoded_content = content.encode("utf-8")
|
|
45
|
-
info.size = len(encoded_content)
|
|
46
|
-
tar.addfile(info, io.BytesIO(encoded_content))
|
|
47
|
-
stream.seek(0)
|
|
48
|
-
return stream
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class DockerContainer(BaseModel):
|
|
52
|
-
config: DockerOperationToolKitConfig = DockerOperationToolKitConfig()
|
|
53
|
-
_container: Container | None = None
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def container(self) -> Container:
|
|
57
|
-
if not self._container:
|
|
58
|
-
self._container = self._setup_container(self.config)
|
|
59
|
-
return self._container
|
|
60
|
-
|
|
61
|
-
def __del__(self) -> None:
|
|
62
|
-
"""Cleanup the container when the toolkit is destroyed."""
|
|
63
|
-
if container := self._container:
|
|
64
|
-
with suppress(Exception):
|
|
65
|
-
container.stop()
|
|
66
|
-
|
|
67
|
-
def _setup_container(self, config: DockerOperationToolKitConfig) -> Container:
|
|
68
|
-
"""Sets up a persistent container for code execution."""
|
|
69
|
-
client = docker.from_env()
|
|
70
|
-
return client.containers.run(
|
|
71
|
-
self.config.docker_image,
|
|
72
|
-
"tail -f /dev/null", # Keep container running
|
|
73
|
-
detach=True,
|
|
74
|
-
mem_limit=self.config.max_memory,
|
|
75
|
-
network_disabled=not self.config.allow_network,
|
|
76
|
-
remove=True,
|
|
77
|
-
security_opt=["no-new-privileges"], # Prevent privilege escalation
|
|
78
|
-
cap_drop=["ALL"], # Drop all capabilities
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class DockerOperationToolKit(ConfigurableToolKit[DockerOperationToolKitConfig]):
|
|
83
|
-
"""ToolKit for executing Python code and shell commands in a Docker container."""
|
|
84
|
-
|
|
85
|
-
config: DockerOperationToolKitConfig = DockerOperationToolKitConfig()
|
|
86
|
-
docker_container: DockerContainer
|
|
87
|
-
__namespace__ = "docker"
|
|
88
|
-
__prompt_usage_description__: ClassVar[str] = """
|
|
89
|
-
- Tools for code execution:
|
|
90
|
-
- ExecutePython: Executes Python code with optional requirements in a Docker container
|
|
91
|
-
- ExecuteShell: Executes shell commands in a Docker container
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
def create_tools(self) -> list[type[BaseTool]]:
|
|
95
|
-
"""The method to create the tools."""
|
|
96
|
-
|
|
97
|
-
tools = super().create_tools()
|
|
98
|
-
for tool in tools:
|
|
99
|
-
if issubclass(tool, DockerOperation):
|
|
100
|
-
tool._docker_container = self.docker_container
|
|
101
|
-
return tools
|
|
102
|
-
|
|
103
|
-
@toolkit_tool
|
|
104
|
-
class ExecutePython(DockerOperation):
|
|
105
|
-
"""Tool for executing Python code in a Docker container."""
|
|
106
|
-
|
|
107
|
-
code: str
|
|
108
|
-
requirements: list[str] | None = None
|
|
109
|
-
|
|
110
|
-
def call(self) -> str:
|
|
111
|
-
"""Executes Python code in a Docker container.
|
|
112
|
-
|
|
113
|
-
docker_image: {self.__config__.docker_image}
|
|
114
|
-
allow_network: {self.__config__.allow_network}
|
|
115
|
-
|
|
116
|
-
Returns:
|
|
117
|
-
str: Output of the code execution
|
|
118
|
-
"""
|
|
119
|
-
try:
|
|
120
|
-
contents = {
|
|
121
|
-
"main.py": self.code,
|
|
122
|
-
}
|
|
123
|
-
if self.requirements:
|
|
124
|
-
if not self._get_config().allow_network:
|
|
125
|
-
return "Error: Network access is disabled. Cannot install requirements via pip."
|
|
126
|
-
contents["requirements.txt"] = "\n".join(self.requirements)
|
|
127
|
-
stream = self._create_tar_stream(contents)
|
|
128
|
-
self._docker_container.container.put_archive("/", stream)
|
|
129
|
-
if self.requirements:
|
|
130
|
-
exit_code, output = self._docker_container.container.exec_run(
|
|
131
|
-
cmd=["pip", "install", "-r", "/requirements.txt"],
|
|
132
|
-
)
|
|
133
|
-
if exit_code != 0: # pragma: no cover
|
|
134
|
-
return (
|
|
135
|
-
f"Error installing requirements: {output.decode('utf-8')}"
|
|
136
|
-
)
|
|
137
|
-
exit_code, output = self._docker_container.container.exec_run(
|
|
138
|
-
cmd=["python", "/main.py"],
|
|
139
|
-
)
|
|
140
|
-
return output.decode("utf-8")
|
|
141
|
-
|
|
142
|
-
except Exception as e:
|
|
143
|
-
return f"Error executing code: {str(e)}"
|
|
144
|
-
|
|
145
|
-
@toolkit_tool
|
|
146
|
-
class ExecuteShell(DockerOperation):
|
|
147
|
-
"""Tool for executing shell commands in a Docker container."""
|
|
148
|
-
|
|
149
|
-
command: str
|
|
150
|
-
|
|
151
|
-
def call(self) -> str:
|
|
152
|
-
"""Executes shell commands in a Docker container.
|
|
153
|
-
|
|
154
|
-
docker_image: {self.__config__.docker_image}
|
|
155
|
-
allow_network: {self.__config__.allow_network}
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
str: Output of the command execution
|
|
159
|
-
"""
|
|
160
|
-
try:
|
|
161
|
-
exec_result = self._docker_container.container.exec_run(
|
|
162
|
-
cmd=["sh", "-c", self.command],
|
|
163
|
-
)
|
|
164
|
-
return exec_result.output.decode("utf-8")
|
|
165
|
-
except Exception as e: # pragma: no cover
|
|
166
|
-
return f"Error executing command: {str(e)}"
|