Skip to main content
Glama

@arizeai/phoenix-mcp

Official
by Arize-ai
test_models.py29 kB
from contextlib import AbstractContextManager, nullcontext from typing import Any, Optional import pytest from phoenix.db.types.model_provider import ModelProvider from phoenix.server.api.helpers.prompts.models import ( PromptAnthropicInvocationParametersContent, denormalize_tools, normalize_tools, ) @pytest.mark.parametrize( "tool_schema", [ pytest.param( { "type": "function", "function": { "name": "get_weather", "parameters": { "type": "object", "properties": {"location": {"type": "string"}}, }, }, }, id="get-weather-function", ), pytest.param( { "type": "function", "function": { "name": "get_delivery_date", "description": "Get the delivery date for a customer's order. Call this whenever you need to know the delivery date, for example when a customer asks 'Where is my package'", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "The customer's order ID.", } }, "required": ["order_id"], "additionalProperties": False, }, }, }, id="get-delivery-date-function", ), pytest.param( { "type": "function", "function": { "name": "generate_recipe", "description": "Generate a recipe based on the user's input", "parameters": { "type": "object", "properties": { "title": { "type": "string", "description": "Title of the recipe.", }, "ingredients": { "type": "array", "items": {"type": "string"}, "description": "List of ingredients required for the recipe.", }, "instructions": { "type": "array", "items": {"type": "string"}, "description": "Step-by-step instructions for the recipe.", }, }, "required": ["title", "ingredients", "instructions"], "additionalProperties": False, }, }, }, id="generate-recipe-function", ), pytest.param( { "type": "function", "function": { "name": "get_product_recommendations", "description": "Searches for products matching certain criteria in the database", "parameters": { "type": "object", "properties": { "categories": { "description": "categories that could be a match", "type": "array", "items": { "type": "string", "enum": [ "coats & jackets", "accessories", "tops", "jeans & trousers", "skirts & dresses", "shoes", ], }, }, "colors": { "description": "colors that could be a match, empty array if N/A", "type": "array", "items": { "type": "string", "enum": [ "black", "white", "brown", "red", "blue", "green", "orange", "yellow", "pink", "gold", "silver", ], }, }, "keywords": { "description": "keywords that should be present in the item title or description", "type": "array", "items": {"type": "string"}, }, "price_range": { "type": "object", "properties": { "min": {"type": "number"}, "max": {"type": "number"}, }, "required": ["min", "max"], "additionalProperties": False, }, "limit": { "type": "integer", "description": "The maximum number of products to return, use 5 by default if nothing is specified by the user", }, }, "required": ["categories", "colors", "keywords", "price_range", "limit"], "additionalProperties": False, }, }, }, id="get-product-recommendations-function", ), pytest.param( { "type": "function", "function": { "name": "get_product_details", "description": "Fetches more details about a product", "parameters": { "type": "object", "properties": { "product_id": { "type": "string", "description": "The ID of the product to fetch details for", } }, "required": ["product_id"], "additionalProperties": False, }, }, }, id="get-product-details-function", ), pytest.param( { "type": "function", "function": { "name": "add_to_cart", "description": "Add items to cart when the user has confirmed their interest.", "parameters": { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "product_id": { "type": "string", "description": "ID of the product to add to the cart", }, "quantity": { "type": "integer", "description": "Quantity of the product to add to the cart", }, }, "required": ["product_id", "quantity"], "additionalProperties": False, }, } }, "required": ["items"], "additionalProperties": False, }, }, }, id="add-to-cart-function", ), pytest.param( { "type": "function", "function": { "name": "get_order_details", "description": "Fetches details about a specific order", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "The ID of the order to fetch details for", } }, "required": ["order_id"], "additionalProperties": False, }, }, }, id="get-order-details-function", ), pytest.param( { "type": "function", "function": { "name": "get_user_orders", "description": "Fetches the last orders for a given user", "parameters": { "type": "object", "properties": { "user_id": { "type": "string", "description": "The ID of the user to fetch orders for", }, "limit": { "type": "integer", "description": "The maximum number of orders to return, use 5 by default and increase the number if the relevant order is not found.", }, }, "required": ["user_id", "limit"], "additionalProperties": False, }, }, }, id="get-user-orders-function", ), pytest.param( { "type": "function", "function": { "name": "search_faq", "description": "Searches the FAQ for an answer to the user's question", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "The question to search the FAQ for", } }, "required": ["query"], "additionalProperties": False, }, }, }, id="search-faq-function", ), pytest.param( { "type": "function", "function": { "name": "process_return", "description": "Processes a return and creates a return label", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "The ID of the order to process a return for", }, "items": { "type": "array", "description": "The items to return", "items": { "type": "object", "properties": { "product_id": { "type": "string", "description": "The ID of the product to return", }, "quantity": { "type": "integer", "description": "The quantity of the product to return", }, }, "required": ["product_id", "quantity"], "additionalProperties": False, }, }, }, "required": ["order_id", "items"], "additionalProperties": False, }, }, }, id="process-return-function", ), pytest.param( { "type": "function", "function": { "name": "get_return_status", "description": "Finds the status of a return", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "The ID of the order to fetch the return status for", } }, "required": ["order_id"], "additionalProperties": False, }, }, }, id="get-return-status-function", ), pytest.param( { "type": "function", "function": { "name": "get_recommendations", "description": "Fetches recommendations based on the user's preferences", "parameters": { "type": "object", "properties": { "type": { "type": "string", "description": "The type of place to search recommendations for", "enum": ["restaurant", "hotel"], }, "keywords": { "type": "array", "description": "Keywords that should be present in the recommendations", "items": {"type": "string"}, }, "location": { "type": "string", "description": "The location to search recommendations for", }, }, "required": ["type", "keywords", "location"], "additionalProperties": False, }, }, }, id="get-recommendations-function", ), pytest.param( { "type": "function", "function": { "name": "show_on_map", "description": "Places pins on the map for relevant locations", "parameters": { "type": "object", "properties": { "pins": { "type": "array", "description": "The pins to place on the map", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of the place", }, "coordinates": { "type": "object", "properties": { "latitude": {"type": "number"}, "longitude": {"type": "number"}, }, "required": ["latitude", "longitude"], "additionalProperties": False, }, }, "required": ["name", "coordinates"], "additionalProperties": False, }, }, }, "required": ["pins"], "additionalProperties": False, }, }, }, id="show-on-map-function", ), pytest.param( { "type": "function", "function": { "name": "fetch_availability", "description": "Fetches the availability for a given place", "parameters": { "type": "object", "properties": { "place_id": { "type": "string", "description": "The ID of the place to fetch availability for", } }, }, }, }, id="fetch-availability-function", ), pytest.param( { "type": "function", "function": { "name": "create_booking", "description": "Creates a booking on the user's behalf", "parameters": { "type": "object", "properties": { "place_id": { "type": "string", "description": "The ID of the place to create a booking for", }, "booking_details": { "anyOf": [ { "type": "object", "description": "Restaurant booking with specific date and time", "properties": { "date": { "type": "string", "description": "The date of the booking, in format YYYY-MM-DD", }, "time": { "type": "string", "description": "The time of the booking, in format HH:MM", }, }, "required": ["date", "time"], }, { "type": "object", "description": "Hotel booking with specific check-in and check-out dates", "properties": { "check_in": { "type": "string", "description": "The check-in date of the booking, in format YYYY-MM-DD", }, "check_out": { "type": "string", "description": "The check-out date of the booking, in format YYYY-MM-DD", }, }, "required": ["check_in", "check_out"], }, ], }, }, "required": ["place_id", "booking_details"], "additionalProperties": False, }, }, }, id="create-booking-function", ), pytest.param( { "type": "function", "function": { "name": "pick_tshirt_size", "description": "Call this if the user specifies which size t-shirt they want", "parameters": { "type": "object", "properties": { "size": { "type": "string", "enum": ["s", "m", "l"], "description": "The size of the t-shirt that the user would like to order", } }, "required": ["size"], "additionalProperties": False, }, }, }, id="pick-tshirt-size-function", ), ], ) def test_valid_openai_tool_schemas_can_be_normalized_and_denormalized_without_data_loss( tool_schema: dict[str, Any], ) -> None: normalized_tools = normalize_tools([tool_schema], ModelProvider.OPENAI) denormalized_tools, _ = denormalize_tools(normalized_tools, ModelProvider.OPENAI) assert len(denormalized_tools) == 1 assert denormalized_tools[0] == tool_schema @pytest.mark.parametrize( "tool_schema", [ pytest.param( { "name": "get_weather", "description": "Get the current weather in a given location", "input_schema": { "type": "object", "properties": { "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA", }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": 'The unit of temperature, either "celsius" or "fahrenheit"', }, }, "required": ["location"], }, }, id="get-weather-function", ), pytest.param( { "name": "get_time", "description": "Get the current time in a given time zone", "input_schema": { "type": "object", "properties": { "timezone": { "type": "string", "description": "The IANA time zone name, e.g. America/Los_Angeles", } }, "required": ["timezone"], }, }, id="get-time-function", ), pytest.param( { "name": "get_location", "description": "Get the current user location based on their IP address. This tool has no parameters or arguments.", "input_schema": {"type": "object", "properties": {}}, }, id="get-location-function", ), pytest.param( { "name": "record_summary", "description": "Record summary of an image using well-structured JSON.", "input_schema": { "type": "object", "properties": { "key_colors": { "type": "array", "items": { "type": "object", "properties": { "r": {"type": "number", "description": "red value [0.0, 1.0]"}, "g": { "type": "number", "description": "green value [0.0, 1.0]", }, "b": {"type": "number", "description": "blue value [0.0, 1.0]"}, "name": { "type": "string", "description": 'Human-readable color name in snake_case, e.g., "olive_green" or "turquoise"', }, }, "required": ["r", "g", "b", "name"], }, "description": "Key colors in the image. Limit to less then four.", }, "description": { "type": "string", "description": "Image description. One to two sentences max.", }, "estimated_year": { "type": "integer", "description": "Estimated year that the images was taken, if is it a photo. Only set this if the image appears to be non-fictional. Rough estimates are okay!", }, }, "required": ["key_colors", "description"], }, }, id="record-image-summary", ), pytest.param( { "name": "get_weather", "input_schema": { "type": "object", "properties": {"location": {"type": "string"}}, }, }, id="get-weather-function-cache-control-ephemeral", ), pytest.param( { "name": "get_weather", "input_schema": { "type": "object", "properties": {"location": {"type": "string"}}, }, }, id="get-weather-function-cache-control-none", ), ], ) def test_valid_anthropic_tool_schemas_can_be_normalized_and_denormalized_without_data_loss( tool_schema: dict[str, Any], ) -> None: normalized_tools = normalize_tools([tool_schema], ModelProvider.ANTHROPIC) denormalized_tools, _ = denormalize_tools(normalized_tools, ModelProvider.ANTHROPIC) assert len(denormalized_tools) == 1 assert denormalized_tools[0] == tool_schema @pytest.mark.parametrize( "params,expectation", [ pytest.param( {"max_tokens": 1025, "thinking": {"type": "enabled", "budget_tokens": 1024}}, nullcontext(), id="max-tokens-gt-budget-tokens-gt-1024", ), pytest.param( {"max_tokens": 128, "thinking": {"type": "disabled"}}, nullcontext(), id="disabled", ), pytest.param( {"max_tokens": 1025, "thinking": {"type": "enabled", "budget_tokens": 1023}}, pytest.raises(ValueError), id="budget-tokens-lt-1024", ), pytest.param( {"max_tokens": 1024, "thinking": {"type": "enabled", "budget_tokens": 1024}}, pytest.raises(ValueError), id="budget-tokens-eq-max-tokens", ), pytest.param( {"max_tokens": 1024, "thinking": {"type": "enabled", "budget_tokens": 1025}}, pytest.raises(ValueError), id="budget-tokens-gt-max-tokens", ), ], ) def test_validation_of_anthropic_thinking_budget_tokens( params: dict[str, Any], expectation: AbstractContextManager[Optional[Exception]], ) -> None: with expectation: PromptAnthropicInvocationParametersContent.model_validate(params)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Arize-ai/phoenix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server