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
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""The `ToolSchema` class for defining tools that LLMs can request be called."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
from collections import namedtuple
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import (
|
|
9
|
+
Annotated,
|
|
10
|
+
Any,
|
|
11
|
+
Generic,
|
|
12
|
+
TypeVar,
|
|
13
|
+
get_args,
|
|
14
|
+
get_origin,
|
|
15
|
+
get_type_hints,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from docstring_parser import parse
|
|
19
|
+
from pydantic import BaseModel, Field, create_model
|
|
20
|
+
from pydantic.fields import FieldInfo
|
|
21
|
+
|
|
22
|
+
from ..content import ToolCall
|
|
23
|
+
from .protocols import AsyncContextToolFn, AsyncToolFn, ContextToolFn, ToolFn
|
|
24
|
+
|
|
25
|
+
ToolFnT = TypeVar(
|
|
26
|
+
"ToolFnT",
|
|
27
|
+
bound=ToolFn | AsyncToolFn | ContextToolFn | AsyncContextToolFn,
|
|
28
|
+
covariant=True,
|
|
29
|
+
)
|
|
30
|
+
ToolSchemaT = TypeVar("ToolSchemaT", bound="ToolSchema")
|
|
31
|
+
|
|
32
|
+
DocstringArg = namedtuple("DocstringArg", ["name", "description"])
|
|
33
|
+
|
|
34
|
+
FORMAT_TOOL_NAME = "__mirascope_formatted_output_tool__"
|
|
35
|
+
"""Reserved name of the formatted output tool.
|
|
36
|
+
|
|
37
|
+
Any call to a tool with this name is NOT considered a regular tool call, but will instead
|
|
38
|
+
be converted into textual output containing the arguments to the tool call.
|
|
39
|
+
"""
|
|
40
|
+
# TODO: Investigate whether using this hardcoded tool name has any adverse impact
|
|
41
|
+
# on model performance, compared to a tool name that references the name of the formatted
|
|
42
|
+
# class.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class ParsedDocstring:
|
|
47
|
+
args: list[DocstringArg]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _parse_docstring_params(docstring: str | None) -> ParsedDocstring:
|
|
51
|
+
"""Parse parameter descriptions from a docstring.
|
|
52
|
+
|
|
53
|
+
Uses docstring-parser library which supports ReST, Google, Numpydoc-style and
|
|
54
|
+
Epydoc docstrings
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
docstring: The function's docstring
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
ParsedDocstring containing parameter descriptions
|
|
61
|
+
"""
|
|
62
|
+
if not docstring:
|
|
63
|
+
return ParsedDocstring(args=[])
|
|
64
|
+
|
|
65
|
+
parsed = parse(docstring)
|
|
66
|
+
args = []
|
|
67
|
+
|
|
68
|
+
for param in parsed.params:
|
|
69
|
+
if param.description:
|
|
70
|
+
args.append(
|
|
71
|
+
DocstringArg(name=param.arg_name, description=param.description)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return ParsedDocstring(args=args)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ToolParameterSchema(BaseModel):
|
|
78
|
+
"""JSON Schema for tool parameters (always an object with properties).
|
|
79
|
+
|
|
80
|
+
This contains real JSON Schema as generated by Pydantic, with full support
|
|
81
|
+
for complex schemas like anyOf, nested objects, validation constraints, etc.
|
|
82
|
+
Including $defs for complex type references.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
properties: dict[str, dict[str, Any]] = Field(default_factory=dict)
|
|
86
|
+
"""Dictionary mapping parameter names to their JSON Schema definitions."""
|
|
87
|
+
|
|
88
|
+
required: list[str] = Field(default_factory=list)
|
|
89
|
+
"""List of required parameter names."""
|
|
90
|
+
|
|
91
|
+
additionalProperties: bool = False
|
|
92
|
+
"""Whether additional properties beyond those defined are allowed."""
|
|
93
|
+
|
|
94
|
+
defs: dict[str, dict[str, Any]] | None = Field(default=None, alias="$defs")
|
|
95
|
+
"""JSON Schema definitions for complex types referenced via $ref."""
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class ToolSchema(Generic[ToolFnT]):
|
|
100
|
+
"""Underlying schema defining a tool that can be used by LLMs.
|
|
101
|
+
|
|
102
|
+
A ToolSchema represents a function that can be called by an LLM during a call.
|
|
103
|
+
It includes metadata like name, description, and parameter schema.
|
|
104
|
+
|
|
105
|
+
This class is not instantiated directly but created by the `@tool()` decorator.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
fn: ToolFnT
|
|
109
|
+
"""The function that implements the tool's functionality."""
|
|
110
|
+
|
|
111
|
+
name: str
|
|
112
|
+
"""The name of the tool, used by the LLM to identify which tool to call."""
|
|
113
|
+
|
|
114
|
+
description: str
|
|
115
|
+
"""Description of what the tool does, extracted from the function's docstring."""
|
|
116
|
+
|
|
117
|
+
parameters: ToolParameterSchema
|
|
118
|
+
"""JSON Schema describing the parameters accepted by the tool.
|
|
119
|
+
|
|
120
|
+
The serialized parameters table is cached for efficient hash lookups (e.g. when
|
|
121
|
+
caching provider-encoded tool representations in a LRU cache). Therefore,
|
|
122
|
+
it should **not be modified** after the ToolSchema is created.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
strict: bool
|
|
126
|
+
"""Whether the tool should use strict mode when supported by the model."""
|
|
127
|
+
|
|
128
|
+
def __hash__(self) -> int:
|
|
129
|
+
if not hasattr(self, "_hash"):
|
|
130
|
+
self._hash = hash(
|
|
131
|
+
(
|
|
132
|
+
self.name,
|
|
133
|
+
self.description,
|
|
134
|
+
self.strict,
|
|
135
|
+
self.parameters.model_dump_json(),
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
return self._hash
|
|
139
|
+
|
|
140
|
+
def __init__(
|
|
141
|
+
self,
|
|
142
|
+
fn: ToolFnT,
|
|
143
|
+
*,
|
|
144
|
+
strict: bool = False,
|
|
145
|
+
is_context_tool: bool = False,
|
|
146
|
+
) -> None:
|
|
147
|
+
"""Create a `ToolSchema` by inspecting a function and its docstring.
|
|
148
|
+
|
|
149
|
+
Uses Pydantic's create_model to dynamically build a model from the function
|
|
150
|
+
signature, then extracts the JSON schema from it. This leverages Pydantic's
|
|
151
|
+
robust type conversion and union handling.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
fn: The function to extract schema from
|
|
155
|
+
strict: Whether the tool should use strict mode when supported
|
|
156
|
+
is_context_tool: Whether this is a context tool (skips the context parameter)
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
a `ToolSchema` representing the function
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
ValueError: If the tool has a reserved name.
|
|
163
|
+
"""
|
|
164
|
+
name = fn.__name__
|
|
165
|
+
if name.startswith(FORMAT_TOOL_NAME):
|
|
166
|
+
raise ValueError(
|
|
167
|
+
f"Cannot use reserved name {FORMAT_TOOL_NAME} as tool name."
|
|
168
|
+
)
|
|
169
|
+
description = inspect.cleandoc(fn.__doc__) if fn.__doc__ else name
|
|
170
|
+
|
|
171
|
+
param_descriptions = _parse_docstring_params(fn.__doc__)
|
|
172
|
+
|
|
173
|
+
field_definitions = {}
|
|
174
|
+
hints = get_type_hints(fn, include_extras=True)
|
|
175
|
+
|
|
176
|
+
context_param_skipped = False
|
|
177
|
+
for param in inspect.signature(fn).parameters.values():
|
|
178
|
+
# Skip args that are provided by Python or Mirascope, not LLM-generated.
|
|
179
|
+
# TODO: Handling of FromCallArgs
|
|
180
|
+
if param.name in ("self", "cls"):
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
# For context tools, skip the first non-self/cls parameter (the context parameter)
|
|
184
|
+
if is_context_tool and not context_param_skipped:
|
|
185
|
+
context_param_skipped = True
|
|
186
|
+
continue
|
|
187
|
+
|
|
188
|
+
param_type = hints.get(param.name, Any)
|
|
189
|
+
default = ... if param.default is inspect.Parameter.empty else param.default
|
|
190
|
+
field_info = None
|
|
191
|
+
|
|
192
|
+
if get_origin(param_type) is Annotated:
|
|
193
|
+
args = get_args(param_type)
|
|
194
|
+
param_type = args[0]
|
|
195
|
+
for annotation in args[1:]:
|
|
196
|
+
if isinstance(annotation, FieldInfo):
|
|
197
|
+
field_info = annotation
|
|
198
|
+
break
|
|
199
|
+
|
|
200
|
+
if field_info is not None:
|
|
201
|
+
field_value = Field(
|
|
202
|
+
default=default,
|
|
203
|
+
description=field_info.description,
|
|
204
|
+
)
|
|
205
|
+
else:
|
|
206
|
+
docstring_description = None
|
|
207
|
+
for arg in param_descriptions.args:
|
|
208
|
+
if arg.name == param.name:
|
|
209
|
+
docstring_description = arg.description
|
|
210
|
+
break
|
|
211
|
+
if docstring_description:
|
|
212
|
+
field_value = Field(
|
|
213
|
+
default=default, description=docstring_description
|
|
214
|
+
)
|
|
215
|
+
else:
|
|
216
|
+
field_value = default
|
|
217
|
+
|
|
218
|
+
field_definitions[param.name] = (param_type, field_value)
|
|
219
|
+
|
|
220
|
+
TempModel = create_model("TempModel", **field_definitions)
|
|
221
|
+
|
|
222
|
+
schema = TempModel.model_json_schema()
|
|
223
|
+
|
|
224
|
+
parameters = ToolParameterSchema(
|
|
225
|
+
properties=schema.get("properties", {}),
|
|
226
|
+
required=schema.get("required", []),
|
|
227
|
+
additionalProperties=False,
|
|
228
|
+
)
|
|
229
|
+
if "$defs" in schema:
|
|
230
|
+
parameters.defs = schema["$defs"]
|
|
231
|
+
|
|
232
|
+
self.fn = fn
|
|
233
|
+
self.name = name
|
|
234
|
+
self.description = description
|
|
235
|
+
self.parameters = parameters
|
|
236
|
+
self.strict = strict
|
|
237
|
+
|
|
238
|
+
def can_execute(self, tool_call: ToolCall) -> bool:
|
|
239
|
+
"""Check if a `ToolCall` can be executed by tools with this `ToolSchema`.
|
|
240
|
+
|
|
241
|
+
This method is a convenient way to determine if a `ToolCall` is likely intended
|
|
242
|
+
to be executed by a tool with this `ToolSchema`. It does so by checking
|
|
243
|
+
whether the name on the call matches the name on the schema. No other validation
|
|
244
|
+
is performed.
|
|
245
|
+
"""
|
|
246
|
+
return tool_call.name == self.name
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, Generic, TypeVar
|
|
4
|
+
|
|
5
|
+
from ..content import ToolCall, ToolOutput
|
|
6
|
+
from ..context import Context, DepsT
|
|
7
|
+
from ..exceptions import ToolNotFoundError
|
|
8
|
+
from ..types import Jsonable
|
|
9
|
+
from .tool_schema import ToolSchemaT
|
|
10
|
+
from .tools import AsyncContextTool, AsyncTool, ContextTool, Tool
|
|
11
|
+
|
|
12
|
+
ToolkitT = TypeVar(
|
|
13
|
+
"ToolkitT",
|
|
14
|
+
bound="Toolkit | AsyncToolkit | ContextToolkit[Any] | AsyncContextToolkit[Any]",
|
|
15
|
+
covariant=True,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class BaseToolkit(Generic[ToolSchemaT]):
|
|
21
|
+
"""Base class for tool collections.
|
|
22
|
+
|
|
23
|
+
Provides common functionality for managing collections of tools,
|
|
24
|
+
including name validation and tool lookup.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
tools: Sequence[ToolSchemaT]
|
|
28
|
+
"""The tools included in the toolkit."""
|
|
29
|
+
|
|
30
|
+
tools_dict: dict[str, ToolSchemaT]
|
|
31
|
+
"""A mapping from tool names to tools in the toolkit."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, tools: Sequence[ToolSchemaT] | None) -> None:
|
|
34
|
+
"""Initialize the toolkit with a collection of tools.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
tools: Sequence of tools to include in the toolkit.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
ValueError: If multiple tools have the same name.
|
|
41
|
+
"""
|
|
42
|
+
self.tools = tools or []
|
|
43
|
+
self.tools_dict = {}
|
|
44
|
+
for tool in self.tools:
|
|
45
|
+
if tool.name in self.tools_dict:
|
|
46
|
+
raise ValueError(f"Multiple tools with name: {tool.name}")
|
|
47
|
+
self.tools_dict[tool.name] = tool
|
|
48
|
+
|
|
49
|
+
def get(self, tool_call: ToolCall) -> ToolSchemaT:
|
|
50
|
+
"""Get a tool that can execute a specific tool call.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
tool_call: The tool call containing the tool name to lookup.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The tool whose name matches the tool call.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ToolNotFoundError: If no tool with the given name exists.
|
|
60
|
+
"""
|
|
61
|
+
tool = self.tools_dict.get(tool_call.name, None)
|
|
62
|
+
if not tool:
|
|
63
|
+
raise ToolNotFoundError(f"Tool not found in toolkit: {tool_call.name}")
|
|
64
|
+
return tool
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Toolkit(BaseToolkit[Tool]):
|
|
68
|
+
"""A collection of `Tool`s, with helpers for getting and executing specific tools."""
|
|
69
|
+
|
|
70
|
+
def execute(self, tool_call: ToolCall) -> ToolOutput[Jsonable]:
|
|
71
|
+
"""Execute a `Tool` using the provided tool call.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
tool_call: The tool call to execute.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The output from executing the `Tool`.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
ToolNotFoundError: If the requested tool is not found.
|
|
81
|
+
"""
|
|
82
|
+
tool = self.get(tool_call)
|
|
83
|
+
return tool.execute(tool_call)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class AsyncToolkit(BaseToolkit[AsyncTool]):
|
|
87
|
+
"""A collection of `AsyncTool`s, with helpers for getting and executing specific tools."""
|
|
88
|
+
|
|
89
|
+
async def execute(self, tool_call: ToolCall) -> ToolOutput[Jsonable]:
|
|
90
|
+
"""Execute an `AsyncTool` using the provided tool call.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
tool_call: The tool call to execute.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
The output from executing the `AsyncTool`.
|
|
97
|
+
|
|
98
|
+
Raises:
|
|
99
|
+
ToolNotFoundError: If the requested tool is not found.
|
|
100
|
+
"""
|
|
101
|
+
tool = self.get(tool_call)
|
|
102
|
+
return await tool.execute(tool_call)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class ContextToolkit(BaseToolkit[Tool | ContextTool[DepsT]], Generic[DepsT]):
|
|
106
|
+
"""A collection of `ContextTool`s, with helpers for getting and executing specific tools."""
|
|
107
|
+
|
|
108
|
+
def execute(self, ctx: Context[DepsT], tool_call: ToolCall) -> ToolOutput[Jsonable]:
|
|
109
|
+
"""Execute a `ContextTool` using the provided tool call.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
ctx: The context containing dependencies that match the tool.
|
|
113
|
+
tool_call: The tool call to execute.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
The output from executing the `ContextTool`.
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
ToolNotFoundError: If the requested tool is not found.
|
|
120
|
+
"""
|
|
121
|
+
tool = self.get(tool_call)
|
|
122
|
+
if isinstance(tool, ContextTool):
|
|
123
|
+
return tool.execute(ctx, tool_call)
|
|
124
|
+
else:
|
|
125
|
+
return tool.execute(tool_call)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class AsyncContextToolkit(
|
|
129
|
+
BaseToolkit[AsyncTool | AsyncContextTool[DepsT]], Generic[DepsT]
|
|
130
|
+
):
|
|
131
|
+
"""A collection of `AsyncContextTool`s, with helpers for getting and executing specific tools."""
|
|
132
|
+
|
|
133
|
+
async def execute(
|
|
134
|
+
self, ctx: Context[DepsT], tool_call: ToolCall
|
|
135
|
+
) -> ToolOutput[Jsonable]:
|
|
136
|
+
"""Execute an `AsyncContextTool` using the provided tool call.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
ctx: The context containing dependencies that match the tool.
|
|
140
|
+
tool_call: The tool call to execute.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
The output from executing the `AsyncContextTool`.
|
|
144
|
+
|
|
145
|
+
Raises:
|
|
146
|
+
ToolNotFoundError: If the requested tool is not found.
|
|
147
|
+
"""
|
|
148
|
+
tool = self.get(tool_call)
|
|
149
|
+
if isinstance(tool, AsyncContextTool):
|
|
150
|
+
return await tool.execute(ctx, tool_call)
|
|
151
|
+
else:
|
|
152
|
+
return await tool.execute(tool_call)
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""The `Tool` class for defining tools that LLMs can request be called."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from collections.abc import Awaitable
|
|
7
|
+
from typing import Any, Generic, TypeVar, cast
|
|
8
|
+
|
|
9
|
+
from ..content import ToolCall, ToolOutput
|
|
10
|
+
from ..context import Context, DepsT
|
|
11
|
+
from ..types import AnyP, JsonableCovariantT
|
|
12
|
+
from .protocols import (
|
|
13
|
+
AsyncContextToolFn,
|
|
14
|
+
AsyncToolFn,
|
|
15
|
+
ContextToolFn,
|
|
16
|
+
ToolFn,
|
|
17
|
+
_AsyncJsonKwargsCallable,
|
|
18
|
+
_AsyncKwargsCallable,
|
|
19
|
+
_ContextKwargsCallable,
|
|
20
|
+
_KwargsCallable,
|
|
21
|
+
)
|
|
22
|
+
from .tool_schema import ToolSchema
|
|
23
|
+
|
|
24
|
+
ToolT = TypeVar(
|
|
25
|
+
"ToolT",
|
|
26
|
+
bound="Tool | AsyncTool | ContextTool[Any] | AsyncContextTool[Any]",
|
|
27
|
+
covariant=True,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Tool(
|
|
32
|
+
ToolSchema[ToolFn[AnyP, JsonableCovariantT]], Generic[AnyP, JsonableCovariantT]
|
|
33
|
+
):
|
|
34
|
+
"""A tool that can be used by LLMs.
|
|
35
|
+
|
|
36
|
+
A `Tool` represents a function that can be called by an LLM during a call.
|
|
37
|
+
It includes metadata like name, description, and parameter schema.
|
|
38
|
+
|
|
39
|
+
This class is not instantiated directly but created by the `@tool()` decorator.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self, fn: ToolFn[AnyP, JsonableCovariantT], *, strict: bool = False
|
|
44
|
+
) -> None:
|
|
45
|
+
super().__init__(fn, strict=strict, is_context_tool=False)
|
|
46
|
+
|
|
47
|
+
def __call__(self, *args: AnyP.args, **kwargs: AnyP.kwargs) -> JsonableCovariantT:
|
|
48
|
+
"""Call the underlying function directly."""
|
|
49
|
+
return self.fn(*args, **kwargs)
|
|
50
|
+
|
|
51
|
+
def execute(self, tool_call: ToolCall) -> ToolOutput[JsonableCovariantT]:
|
|
52
|
+
"""Execute the tool using an LLM-provided `ToolCall`."""
|
|
53
|
+
kwargs_from_json = json.loads(tool_call.args)
|
|
54
|
+
kwargs_callable = cast(_KwargsCallable[JsonableCovariantT], self.fn)
|
|
55
|
+
result = kwargs_callable(**kwargs_from_json)
|
|
56
|
+
return ToolOutput(id=tool_call.id, value=result, name=self.name)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class AsyncTool(
|
|
60
|
+
ToolSchema[AsyncToolFn[AnyP, JsonableCovariantT]],
|
|
61
|
+
Generic[AnyP, JsonableCovariantT],
|
|
62
|
+
):
|
|
63
|
+
"""An async tool that can be used by LLMs.
|
|
64
|
+
|
|
65
|
+
An `AsyncTool` represents an async function that can be called by an LLM during a call.
|
|
66
|
+
It includes metadata like name, description, and parameter schema.
|
|
67
|
+
|
|
68
|
+
This class is not instantiated directly but created by the `@tool()` decorator.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self, fn: AsyncToolFn[AnyP, JsonableCovariantT], *, strict: bool = False
|
|
73
|
+
) -> None:
|
|
74
|
+
super().__init__(fn, strict=strict, is_context_tool=False)
|
|
75
|
+
|
|
76
|
+
def __call__(
|
|
77
|
+
self, *args: AnyP.args, **kwargs: AnyP.kwargs
|
|
78
|
+
) -> Awaitable[JsonableCovariantT]:
|
|
79
|
+
"""Call the underlying async function directly."""
|
|
80
|
+
return self.fn(*args, **kwargs)
|
|
81
|
+
|
|
82
|
+
async def execute(self, tool_call: ToolCall) -> ToolOutput[JsonableCovariantT]:
|
|
83
|
+
"""Execute the async tool using an LLM-provided `ToolCall`."""
|
|
84
|
+
kwargs_from_json = json.loads(tool_call.args)
|
|
85
|
+
kwargs_callable = cast(_AsyncKwargsCallable[JsonableCovariantT], self.fn)
|
|
86
|
+
result = await kwargs_callable(**kwargs_from_json)
|
|
87
|
+
return ToolOutput(id=tool_call.id, value=result, name=self.name)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ContextTool(
|
|
91
|
+
ToolSchema[ContextToolFn[DepsT, AnyP, JsonableCovariantT]],
|
|
92
|
+
Generic[DepsT, AnyP, JsonableCovariantT],
|
|
93
|
+
):
|
|
94
|
+
"""Protocol defining a tool that can be used by LLMs.
|
|
95
|
+
|
|
96
|
+
A `ContextTool` represents a function that can be called by an LLM during a call.
|
|
97
|
+
It includes metadata like name, description, and parameter schema.
|
|
98
|
+
|
|
99
|
+
This class is not instantiated directly but created by the `@tool()` decorator.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
fn: ContextToolFn[DepsT, AnyP, JsonableCovariantT],
|
|
105
|
+
*,
|
|
106
|
+
strict: bool = False,
|
|
107
|
+
) -> None:
|
|
108
|
+
super().__init__(fn, strict=strict, is_context_tool=True)
|
|
109
|
+
|
|
110
|
+
def __call__(
|
|
111
|
+
self,
|
|
112
|
+
ctx: Context[DepsT],
|
|
113
|
+
*args: AnyP.args,
|
|
114
|
+
**kwargs: AnyP.kwargs,
|
|
115
|
+
) -> JsonableCovariantT:
|
|
116
|
+
"""Call the underlying function directly with context."""
|
|
117
|
+
return self.fn(ctx, *args, **kwargs)
|
|
118
|
+
|
|
119
|
+
def execute(
|
|
120
|
+
self, ctx: Context[DepsT], tool_call: ToolCall
|
|
121
|
+
) -> ToolOutput[JsonableCovariantT]:
|
|
122
|
+
"""Execute the context tool using an LLM-provided `ToolCall`."""
|
|
123
|
+
kwargs_from_json = json.loads(tool_call.args)
|
|
124
|
+
kwargs_callable = cast(
|
|
125
|
+
_ContextKwargsCallable[DepsT, JsonableCovariantT], self.fn
|
|
126
|
+
)
|
|
127
|
+
result = kwargs_callable(ctx, **kwargs_from_json)
|
|
128
|
+
return ToolOutput(id=tool_call.id, value=result, name=self.name)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class AsyncContextTool(
|
|
132
|
+
ToolSchema[AsyncContextToolFn[DepsT, AnyP, JsonableCovariantT]],
|
|
133
|
+
Generic[DepsT, AnyP, JsonableCovariantT],
|
|
134
|
+
):
|
|
135
|
+
"""Protocol defining an async tool that can be used by LLMs with context.
|
|
136
|
+
|
|
137
|
+
An `AsyncContextTool` represents an async function that can be called by an LLM during a call.
|
|
138
|
+
It includes metadata like name, description, and parameter schema.
|
|
139
|
+
|
|
140
|
+
This class is not instantiated directly but created by the `@tool()` decorator.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(
|
|
144
|
+
self,
|
|
145
|
+
fn: AsyncContextToolFn[DepsT, AnyP, JsonableCovariantT],
|
|
146
|
+
*,
|
|
147
|
+
strict: bool = False,
|
|
148
|
+
) -> None:
|
|
149
|
+
super().__init__(fn, strict=strict, is_context_tool=True)
|
|
150
|
+
|
|
151
|
+
def __call__(
|
|
152
|
+
self,
|
|
153
|
+
ctx: Context[DepsT],
|
|
154
|
+
*args: AnyP.args,
|
|
155
|
+
**kwargs: AnyP.kwargs,
|
|
156
|
+
) -> Awaitable[JsonableCovariantT]:
|
|
157
|
+
"""Call the underlying async function directly with context."""
|
|
158
|
+
return self.fn(ctx, *args, **kwargs)
|
|
159
|
+
|
|
160
|
+
async def execute(
|
|
161
|
+
self, ctx: Context[DepsT], tool_call: ToolCall
|
|
162
|
+
) -> ToolOutput[JsonableCovariantT]:
|
|
163
|
+
"""Execute the async context tool using an LLM-provided `ToolCall`."""
|
|
164
|
+
kwargs_from_json = json.loads(tool_call.args)
|
|
165
|
+
kwargs_callable = cast(
|
|
166
|
+
_AsyncJsonKwargsCallable[DepsT, JsonableCovariantT], self.fn
|
|
167
|
+
)
|
|
168
|
+
result = await kwargs_callable(ctx, **kwargs_from_json)
|
|
169
|
+
return ToolOutput(id=tool_call.id, value=result, name=self.name)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Types for the LLM module."""
|
|
2
|
+
|
|
3
|
+
from .dataclass import Dataclass
|
|
4
|
+
from .jsonable import (
|
|
5
|
+
Jsonable,
|
|
6
|
+
JsonableCovariantT,
|
|
7
|
+
JsonableT,
|
|
8
|
+
)
|
|
9
|
+
from .type_vars import AnyP, CovariantT, P
|
|
10
|
+
|
|
11
|
+
NoneType = type(None)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AnyP",
|
|
15
|
+
"CovariantT",
|
|
16
|
+
"Dataclass",
|
|
17
|
+
"Jsonable",
|
|
18
|
+
"JsonableCovariantT",
|
|
19
|
+
"JsonableT",
|
|
20
|
+
"NoneType",
|
|
21
|
+
"P",
|
|
22
|
+
]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Typing for JSON serializable objects."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping, Sequence
|
|
4
|
+
from typing import Protocol, TypeAlias
|
|
5
|
+
from typing_extensions import TypeVar
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class JsonableObject(Protocol):
|
|
9
|
+
"""Protocol for JSON-serializable objects.
|
|
10
|
+
|
|
11
|
+
This protocol defines the interface for objects that can be serialized to
|
|
12
|
+
JSON. It is used to annotate the `JsonableType` type alias.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def json(self) -> str:
|
|
16
|
+
"""Serialize the object as a JSON string."""
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Jsonable: TypeAlias = (
|
|
21
|
+
None
|
|
22
|
+
| str
|
|
23
|
+
| int
|
|
24
|
+
| float
|
|
25
|
+
| bool
|
|
26
|
+
| Sequence["Jsonable"]
|
|
27
|
+
| Mapping[str, "Jsonable"]
|
|
28
|
+
| JsonableObject
|
|
29
|
+
)
|
|
30
|
+
"""Simple type alias for JSON-serializable types."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
JsonableT = TypeVar("JsonableT", bound=Jsonable)
|
|
34
|
+
"""Type variable for tool output types.
|
|
35
|
+
|
|
36
|
+
This TypeVar represents the return type of tool functions, which must be
|
|
37
|
+
serializable to JSON (bound to Jsonable) for LLM consumption.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
JsonableCovariantT = TypeVar(
|
|
42
|
+
"JsonableCovariantT", covariant=True, bound=Jsonable, default=Jsonable
|
|
43
|
+
)
|
|
44
|
+
"""Type variable for covariant types that are Jsonable."""
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Common TypeVar definitions for the LLM module."""
|
|
2
|
+
|
|
3
|
+
from typing import TypeVar
|
|
4
|
+
from typing_extensions import ParamSpec
|
|
5
|
+
|
|
6
|
+
P = ParamSpec("P")
|
|
7
|
+
"""Parameter specification for function signatures.
|
|
8
|
+
|
|
9
|
+
This ParamSpec is used to preserve function parameter types and signatures
|
|
10
|
+
when wrapping functions with decorators or creating generic callable types.
|
|
11
|
+
It captures both positional and keyword arguments (*args, **kwargs) while
|
|
12
|
+
maintaining their original types.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
AnyP = ParamSpec("AnyP", default=...)
|
|
16
|
+
"""A parameter specification that defaults to ..."""
|
|
17
|
+
|
|
18
|
+
CovariantT = TypeVar("CovariantT", covariant=True)
|
|
19
|
+
"""Type variable for covariant types."""
|