diff --git a/.gitignore b/.gitignore index b7faf40..d85a32d 100644 --- a/.gitignore +++ b/.gitignore @@ -205,3 +205,5 @@ cython_debug/ marimo/_static/ marimo/_lsp/ __marimo__/ + +.vs \ No newline at end of file diff --git a/src/agent/attractions.ipynb b/src/agent/attractions.ipynb index 7d7a7de..10b4045 100644 --- a/src/agent/attractions.ipynb +++ b/src/agent/attractions.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 3, + "execution_count": 109, "id": "4a8c1aa1", "metadata": {}, "outputs": [ @@ -10,8 +10,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "python: c:\\WorkSpace\\Hackathon\\Hackathon-2025\\.venv\\Scripts\\python.exe\n", - "uv: c:\\WorkSpace\\Hackathon\\Hackathon-2025\\.venv\\Scripts\\uv.EXE\n" + "python: c:\\Code\\hackathon\\Hackathon-2025-Berts\\.venv\\Scripts\\python.exe\n", + "uv: c:\\Code\\hackathon\\Hackathon-2025-Berts\\.venv\\Scripts\\uv.EXE\n" ] } ], @@ -24,7 +24,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 110, "id": "7c3a1676", "metadata": {}, "outputs": [ @@ -32,7 +32,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Requirement already satisfied: uv in c:\\workspace\\hackathon\\hackathon-2025\\.venv\\lib\\site-packages (0.8.20)\n", + "Requirement already satisfied: uv in c:\\code\\hackathon\\hackathon-2025-berts\\.venv\\lib\\site-packages (0.8.22)\n", "Note: you may need to restart the kernel to use updated packages.\n" ] }, @@ -40,8 +40,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "\u001b[2mUsing Python 3.13.3 environment at: c:\\WorkSpace\\Hackathon\\Hackathon-2025\\.venv\u001b[0m\n", - "\u001b[2mAudited \u001b[1m13 packages\u001b[0m \u001b[2min 19ms\u001b[0m\u001b[0m\n" + "\u001b[2mUsing Python 3.13.7 environment at: c:\\Code\\hackathon\\Hackathon-2025-Berts\\.venv\u001b[0m\n", + "\u001b[2mAudited \u001b[1m13 packages\u001b[0m \u001b[2min 29ms\u001b[0m\u001b[0m\n" ] } ], @@ -54,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 111, "id": "f6fdf3d8", "metadata": {}, "outputs": [ @@ -94,7 +94,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 112, "id": "f9bc6177", "metadata": {}, "outputs": [ @@ -121,9 +121,9 @@ " try:\n", " # Create MultiServerMCPClient with streamable_http transport\n", " mcp_client = MultiServerMCPClient({\n", - " \"attractions\": {\n", + " \"restaurants\": {\n", " \"transport\": \"streamable_http\",\n", - " \"url\": os.getenv(\"ATTRACTIONS_MCP_URL\")\n", + " \"url\": os.getenv(\"RESTAURANTS_MCP_URL\")\n", " },\n", " \"weather\": {\n", " \"transport\": \"streamable_http\",\n", @@ -145,7 +145,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 113, "id": "5deceb6f", "metadata": {}, "outputs": [ @@ -166,7 +166,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 114, "id": "ab1bb59a", "metadata": {}, "outputs": [ @@ -204,17 +204,17 @@ " print(f\"Loaded {len(tools)} MCP tools: {[tool.name for tool in tools]}\")\n", " \n", " # Create system prompt\n", - " system_prompt = \"\"\"You are a helpful travel assistant that can help users find and book attractions including weather.\n", - " \n", - " You have access to multiple MCP tools for tourist attractions, including:\n", - " - Searching for attractions by location and category\n", - " - Getting detailed attraction information\n", - " - Booking attractions for visitors\n", - " - Getting random attraction suggestions\n", - " - And more...\n", - " \n", - " When users ask about travel plans, use these tools to provide comprehensive information.\n", - " Always be helpful and provide practical advice.\"\"\"\n", + " system_prompt = \"\"\"\n", + " You are an assistant that helps users find restaurants. Use the provided tools to get restaurant data and menus.\n", + "\n", + " Please follow these guidelines:\n", + " - Always use the tools to get restaurant information and menus.\n", + " - If the user asks for dietary information, use the get_menu tool\n", + " - Provide clear and concise responses based on the tool outputs.\n", + " - If you don't know the answer, say you don't know.\n", + " - Do not be too helpful, just provide the data requested based on what is asked.\n", + "\n", + " \"\"\"\n", " \n", " # Create prompt template\n", " prompt = ChatPromptTemplate.from_messages([\n", @@ -242,7 +242,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 115, "id": "881d1451", "metadata": {}, "outputs": [ @@ -251,18 +251,10 @@ "output_type": "stream", "text": [ "Initializing agent with MCP tools...\n", - "Loaded 7 MCP tools: ['get_attraction_details', 'search_attractions', 'get_random_attraction', 'book_attraction', 'search_and_format_attractions', 'get_current_weather', 'get_weather_forecast']\n", - "Loaded 7 MCP tools: ['get_attraction_details', 'search_attractions', 'get_random_attraction', 'book_attraction', 'search_and_format_attractions', 'get_current_weather', 'get_weather_forecast']\n", + "Loaded 4 MCP tools: ['search_restaurants', 'get_menu', 'get_current_weather', 'get_weather_forecast']\n", + "Loaded 4 MCP tools: ['search_restaurants', 'get_menu', 'get_current_weather', 'get_weather_forecast']\n", "LangChain agent with MCP tools ready!\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\JayGregory\\AppData\\Local\\Temp\\ipykernel_51000\\3851623357.py:50: LangChainDeprecationWarning: Please see the migration guide at: https://python.langchain.com/docs/versions/migrating_memory/\n", - " memory = ConversationBufferMemory(memory_key=\"chat_history\", return_messages=True)\n" - ] } ], "source": [ @@ -283,7 +275,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 116, "id": "ba56fc7e", "metadata": {}, "outputs": [ @@ -347,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 117, "id": "4d4447a3", "metadata": {}, "outputs": [ @@ -355,58 +347,29 @@ "name": "stdout", "output_type": "stream", "text": [ - "Loaded 7 MCP tools: ['get_attraction_details', 'search_attractions', 'get_random_attraction', 'book_attraction', 'search_and_format_attractions', 'get_current_weather', 'get_weather_forecast']\n", + "Loaded 4 MCP tools: ['search_restaurants', 'get_menu', 'get_current_weather', 'get_weather_forecast']\n", "MCP HTTP server connected successfully!\n", - "Available tools: ['get_attraction_details', 'search_attractions', 'get_random_attraction', 'book_attraction', 'search_and_format_attractions', 'get_current_weather', 'get_weather_forecast']\n", - " - get_attraction_details: Get detailed information about a specific tourist attraction\n", - "\n", - "Args:\n", - " attraction_id: Unique ID of the attraction\n", - " \n", - "Returns:\n", - " AttractionDetails object as dictionary with attraction info, facilities, and visiting tips\n", - "\n", - " - search_attractions: Search for tourist attractions with optional filters\n", + "Available tools: ['search_restaurants', 'get_menu', 'get_current_weather', 'get_weather_forecast']\n", + " - search_restaurants: Search for restaurants with optional filters\n", "\n", "Args:\n", - " location: Location to search in (e.g., \"Paris\", \"India\", \"Italy\")\n", - " category: Category filter - \"historical\", \"natural\", \"cultural\", \"religious\", \"modern\", \"museums\", \"parks\", \"beaches\", \"mountains\", \"architecture\", \"entertainment\", \"adventure\"\n", - " limit: Maximum number of results (1-100, default: 20)\n", - " \n", - "Returns:\n", - " AttractionsList object as dictionary with matching attractions\n", - "\n", - " - get_random_attraction: Get a random tourist attraction for inspiration\n", + " cuisine: Filter by cuisine type (e.g. \"italian\", \"chinese\")\n", + " location: City name or place name (e.g., \"London\", \"New York\", \"Tokyo\")\n", + " average_price: Filter by maximum average price per person (e.g. 50)\n", + " rating_min: Minimum rating filter (e.g., 4)\n", + " opens_at: Filter by opening hours (e.g. 700)\n", + " closes_at: Filter by closing hours (e.g. 2100)\n", "\n", - "Args:\n", - " region: Region type - \"famous\" for world famous attractions, \"india\" for Indian attractions\n", - " \n", "Returns:\n", - " Attraction object as dictionary with random attraction details\n", + " RestaurantsList object as dictionary with matching restaurants\n", "\n", - " - book_attraction: Book a visit to a tourist attraction\n", + " - get_menu: Get menu for a specific restaurant\n", "\n", "Args:\n", - " attraction_id: ID of the attraction to book\n", - " visitor_name: Name of the primary visitor\n", - " email: Email address for booking confirmation\n", - " visit_date: Visit date in YYYY-MM-DD format\n", - " num_visitors: Number of visitors (1-50, default: 1)\n", - " phone: Optional phone number\n", - " special_requirements: Optional special requirements or requests\n", - " \n", - "Returns:\n", - " BookingResponse object as dictionary with booking confirmation details\n", + " restaurant_id: The ID of the restaurant to get menu for\n", "\n", - " - search_and_format_attractions: Search for attractions and return formatted results for easy reading\n", - "\n", - "Args:\n", - " location: Location to search in (e.g., \"Paris\", \"India\", \"Italy\") \n", - " category: Category filter (e.g., \"historical\", \"natural\", \"cultural\")\n", - " limit: Maximum number of results (1-20, default: 10)\n", - " \n", "Returns:\n", - " Formatted string with attraction search results\n", + " Menu data for the restaurant\n", "\n", " - get_current_weather: Get current weather information for a specific location\n", "\n", @@ -447,7 +410,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 118, "id": "57dcf6ff", "metadata": {}, "outputs": [ @@ -461,36 +424,18 @@ "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `search_and_format_attractions` with `{'location': 'Paris', 'limit': 10}`\n", - "\n", - "\n", - "\u001b[0m\u001b[32;1m\u001b[1;3m\n", "Invoking: `get_current_weather` with `{'location': 'Paris'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m🎯 Found 2 attractions in Paris:\n", - "\n", - "1. 🏛️ **Eiffel Tower**\n", - " 📍 Paris, France\n", - " 🏷️ Architecture\n", - " ⭐ 4.6/5.0\n", - " 💰 €29.40 - €73.30\n", - "\n", - "2. 🏛️ **Louvre Museum**\n", - " 📍 Paris, France\n", - " 🏷️ Museums\n", - " ⭐ 4.4/5.0\n", - " 💰 €17\n", - "\n", - "\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + "\u001b[0m\u001b[38;5;200m\u001b[1;3m{\n", " \"location\": \"Paris, Île-de-France, France\",\n", " \"coordinates\": {\n", " \"lat\": 48.85341,\n", " \"lon\": 2.3488\n", " },\n", " \"temperature\": {\n", - " \"current\": 12.0,\n", - " \"feels_like\": 10.2,\n", + " \"current\": 11.1,\n", + " \"feels_like\": 9.4,\n", " \"min\": null,\n", " \"max\": null,\n", " \"unit\": \"°C\"\n", @@ -500,56 +445,60 @@ " \"code\": 61\n", " },\n", " \"wind\": {\n", - " \"speed\": 16.1,\n", - " \"direction\": 20,\n", + " \"speed\": 13.1,\n", + " \"direction\": 16,\n", " \"unit\": \"km/h\",\n", " \"max_gusts\": null\n", " },\n", - " \"humidity\": 64,\n", - " \"pressure\": 1018.1,\n", + " \"humidity\": 86,\n", + " \"pressure\": 1017.9,\n", " \"precipitation\": 0.6,\n", " \"timezone\": \"Europe/Paris\",\n", - " \"timestamp\": \"2025-09-23T11:45\"\n", - "}\u001b[0m\u001b[32;1m\u001b[1;3mHere are a few quick highlights and the current weather for Paris.\n", - "\n", - "Popular attractions (quick overview)\n", - "- Eiffel Tower — Architecture — Rating ~4.6/5 — Typical ticket range €29–€73\n", - " - Tip: Book a timed ticket in advance to avoid long queues; allow 1–2 hours; great at sunset.\n", - "- Louvre Museum — Museums — Rating ~4.4/5 — Typical ticket ~€17\n", - " - Tip: Closed on Tuesdays; get a timed-entry ticket and plan 2–4 hours (Mona Lisa area is busiest).\n", - "\n", - "Current weather in Paris (Île‑de‑France) — as of 2025-09-23 11:45 (local)\n", - "- Temperature: 12.0°C (feels like 10.2°C)\n", - "- Conditions: Slight rain\n", - "- Precipitation: ~0.6 mm\n", - "- Wind: ~16 km/h from ~20° (NNE)\n", - "- Humidity: 64% · Pressure: ~1018 hPa\n", - "\n", - "Practical suggestions\n", - "- Pack a compact umbrella or a waterproof jacket and wear layers — cool and light rain.\n", - "- For outdoor sights (Eiffel Tower, Seine strolls) prioritize mornings or late afternoons to avoid peak crowds.\n", - "- Want me to: find more attractions by neighborhood or category, get detailed info (hours, accessibility), or book tickets for the Eiffel Tower or Louvre? If you want booking, tell me the visit date, number of visitors, and the name/email to use.\u001b[0m\n", + " \"timestamp\": \"2025-09-24T16:45\"\n", + "}\u001b[0m\u001b[32;1m\u001b[1;3mHere’s a quick snapshot:\n", + "\n", + "Popular attractions in Paris\n", + "- Eiffel Tower\n", + "- Louvre Museum\n", + "- Notre-Dame area / Île de la Cité\n", + "- Montmartre & Sacré-Cœur\n", + "- Musée d'Orsay\n", + "- Arc de Triomphe & Champs-Élysées\n", + "- Centre Pompidou\n", + "- Seine River cruise (boat tour)\n", + "\n", + "Current weather in Paris\n", + "- Condition: Slight rain\n", + "- Temperature: 11.1°C (feels like 9.4°C)\n", + "- Wind: 13.1 km/h from the 16° direction\n", + "- Humidity: 86%\n", + "- Pressure: 1017.9 hPa\n", + "- Precipitation: 0.6 mm\n", + "- Timezone: Europe/Paris\n", + "- Timestamp: 2025-09-24T16:45\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", - "Here are a few quick highlights and the current weather for Paris.\n", - "\n", - "Popular attractions (quick overview)\n", - "- Eiffel Tower — Architecture — Rating ~4.6/5 — Typical ticket range €29–€73\n", - " - Tip: Book a timed ticket in advance to avoid long queues; allow 1–2 hours; great at sunset.\n", - "- Louvre Museum — Museums — Rating ~4.4/5 — Typical ticket ~€17\n", - " - Tip: Closed on Tuesdays; get a timed-entry ticket and plan 2–4 hours (Mona Lisa area is busiest).\n", - "\n", - "Current weather in Paris (Île‑de‑France) — as of 2025-09-23 11:45 (local)\n", - "- Temperature: 12.0°C (feels like 10.2°C)\n", - "- Conditions: Slight rain\n", - "- Precipitation: ~0.6 mm\n", - "- Wind: ~16 km/h from ~20° (NNE)\n", - "- Humidity: 64% · Pressure: ~1018 hPa\n", - "\n", - "Practical suggestions\n", - "- Pack a compact umbrella or a waterproof jacket and wear layers — cool and light rain.\n", - "- For outdoor sights (Eiffel Tower, Seine strolls) prioritize mornings or late afternoons to avoid peak crowds.\n", - "- Want me to: find more attractions by neighborhood or category, get detailed info (hours, accessibility), or book tickets for the Eiffel Tower or Louvre? If you want booking, tell me the visit date, number of visitors, and the name/email to use.\n", + "Here’s a quick snapshot:\n", + "\n", + "Popular attractions in Paris\n", + "- Eiffel Tower\n", + "- Louvre Museum\n", + "- Notre-Dame area / Île de la Cité\n", + "- Montmartre & Sacré-Cœur\n", + "- Musée d'Orsay\n", + "- Arc de Triomphe & Champs-Élysées\n", + "- Centre Pompidou\n", + "- Seine River cruise (boat tour)\n", + "\n", + "Current weather in Paris\n", + "- Condition: Slight rain\n", + "- Temperature: 11.1°C (feels like 9.4°C)\n", + "- Wind: 13.1 km/h from the 16° direction\n", + "- Humidity: 86%\n", + "- Pressure: 1017.9 hPa\n", + "- Precipitation: 0.6 mm\n", + "- Timezone: Europe/Paris\n", + "- Timestamp: 2025-09-24T16:45\n", "\n", "==================================================\n", "\n" @@ -570,7 +519,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 119, "id": "bd0841c0", "metadata": {}, "outputs": [ @@ -579,282 +528,394 @@ "output_type": "stream", "text": [ "Type 'exit' to quit. Press Enter on an empty line to skip.\n", - "🧳 User: give me a random attraction\n", + "🧳 User: can you find me some restaurants in new york and then check if they offer gluten free dishes\n", "🤖 Assistant:\n", "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `get_random_attraction` with `{'region': 'famous'}`\n", + "Invoking: `search_restaurants` with `{'location': 'New York'}`\n", "\n", "\n", - "\u001b[0m\u001b[38;5;200m\u001b[1;3m{\n", - " \"id\": 10,\n", - " \"name\": \"Petra\",\n", - " \"description\": \"Archaeological city famous for rock-cut architecture and water conduit system\",\n", - " \"category\": \"historical\",\n", - " \"location\": {\n", - " \"city\": \"Ma'an\",\n", - " \"country\": \"Jordan\",\n", - " \"region\": \"Ma'an\",\n", - " \"coordinates\": null\n", - " },\n", - " \"rating\": 4.7,\n", - " \"image_url\": \"https://example.com/petra.jpg\",\n", - " \"website\": \"https://www.visitpetra.jo\",\n", - " \"opening_hours\": \"6:00 AM - 6:00 PM\",\n", - " \"entry_fee\": \"70 JOD (1 day), 55 JOD (2 days)\"\n", - "}\u001b[0m\u001b[32;1m\u001b[1;3mGreat choice — here’s a random pick:\n", - "\n", - "Petra (Jordan)\n", - "- What it is: Ancient archaeological city famous for its rock-cut architecture (like the Treasury) and ancient water conduit system.\n", - "- Location: Ma'an Governorate, Jordan.\n", - "- Category: Historical.\n", - "- Rating: 4.7.\n", - "- Opening hours: 6:00 AM – 6:00 PM.\n", - "- Entry fee: 70 JOD (1 day), 55 JOD (2 days).\n", - "- Website: https://www.visitpetra.jo\n", - "- Recommended visit length: 4–6 hours (longer if you plan hikes to the Monastery or Al-Khubtha).\n", - "- Best time to visit: Spring or autumn for milder weather; arrive early to avoid crowds and heat.\n", - "- Practical tips: wear sturdy walking shoes, bring plenty of water and sun protection, consider a guided tour to learn the history, and note some trails can be steep. Petra by Night is a special evening experience on some nights — check schedules in advance.\n", - "\n", - "Would you like more details (hours, accessibility, guided tours), help booking a ticket or tour, or another random attraction?\u001b[0m\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m['{\\n \"id\": \"rest_101\",\\n \"name\": \"Green Bowl\",\\n \"cuisine\": \"healthy\",\\n \"location\": \"New York\",\\n \"average_price\": 25.0,\\n \"rating\": 4.2,\\n \"opens_at\": 700,\\n \"closes_at\": 2100\\n}', '{\\n \"id\": \"rest_102\",\\n \"name\": \"Pizza Palace\",\\n \"cuisine\": \"italian\",\\n \"location\": \"New York\",\\n \"average_price\": 15.0,\\n \"rating\": 3.8,\\n \"opens_at\": 700,\\n \"closes_at\": 2300\\n}', '{\\n \"id\": \"rest_103\",\\n \"name\": \"Sushi Central\",\\n \"cuisine\": \"japanese\",\\n \"location\": \"New York\",\\n \"average_price\": 65.0,\\n \"rating\": 4.6,\\n \"opens_at\": 1700,\\n \"closes_at\": 2200\\n}', '{\\n \"id\": \"rest_105\",\\n \"name\": \"Taco Town\",\\n \"cuisine\": \"mexican\",\\n \"location\": \"New York\",\\n \"average_price\": 12.0,\\n \"rating\": 4.3,\\n \"opens_at\": 1100,\\n \"closes_at\": 2200\\n}']\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_105'}`\n", "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "Great choice — here’s a random pick:\n", - "\n", - "Petra (Jordan)\n", - "- What it is: Ancient archaeological city famous for its rock-cut architecture (like the Treasury) and ancient water conduit system.\n", - "- Location: Ma'an Governorate, Jordan.\n", - "- Category: Historical.\n", - "- Rating: 4.7.\n", - "- Opening hours: 6:00 AM – 6:00 PM.\n", - "- Entry fee: 70 JOD (1 day), 55 JOD (2 days).\n", - "- Website: https://www.visitpetra.jo\n", - "- Recommended visit length: 4–6 hours (longer if you plan hikes to the Monastery or Al-Khubtha).\n", - "- Best time to visit: Spring or autumn for milder weather; arrive early to avoid crowds and heat.\n", - "- Practical tips: wear sturdy walking shoes, bring plenty of water and sun protection, consider a guided tour to learn the history, and note some trails can be steep. Petra by Night is a special evening experience on some nights — check schedules in advance.\n", - "\n", - "Would you like more details (hours, accessibility, guided tours), help booking a ticket or tour, or another random attraction?\n", - "🧳 User: what about attractions in paris\n", - "🤖 Assistant:\n", - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `search_and_format_attractions` with `{'location': 'Paris', 'category': None, 'limit': 10}`\n", "\n", + "\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_102'}`\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m🎯 Found 2 attractions in Paris:\n", "\n", - "1. 🏛️ **Eiffel Tower**\n", - " 📍 Paris, France\n", - " 🏷️ Architecture\n", - " ⭐ 4.6/5.0\n", - " 💰 €29.40 - €73.30\n", + "\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_103'}`\n", "\n", - "2. 🏛️ **Louvre Museum**\n", - " 📍 Paris, France\n", - " 🏷️ Museums\n", - " ⭐ 4.4/5.0\n", - " 💰 €17\n", "\n", "\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `search_attractions` with `{'location': 'Paris', 'category': None, 'limit': 10}`\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_101'}`\n", "\n", "\n", "\u001b[0m\u001b[33;1m\u001b[1;3m{\n", - " \"category\": \"All Categories\",\n", - " \"location\": \"Paris\",\n", - " \"total_count\": 2,\n", - " \"attractions\": [\n", + " \"restaurant_id\": \"rest_101\",\n", + " \"restaurant_name\": \"Green Bowl\",\n", + " \"menu_items\": [\n", " {\n", - " \"id\": 1,\n", - " \"name\": \"Eiffel Tower\",\n", - " \"description\": \"Iconic iron lattice tower located on the Champ de Mars in Paris, France\",\n", - " \"category\": \"architecture\",\n", - " \"location\": {\n", - " \"city\": \"Paris\",\n", - " \"country\": \"France\",\n", - " \"region\": \"Île-de-France\",\n", - " \"coordinates\": null\n", - " },\n", - " \"rating\": 4.6,\n", - " \"image_url\": \"https://example.com/eiffel-tower.jpg\",\n", - " \"website\": \"https://www.toureiffel.paris\",\n", - " \"opening_hours\": \"9:30 AM - 11:45 PM\",\n", - " \"entry_fee\": \"€29.40 - €73.30\"\n", + " \"id\": \"item_rest_101_001\",\n", + " \"name\": \"Quinoa Power Bowl\",\n", + " \"description\": \"Quinoa, kale, avocado, chickpeas, and tahini dressing\",\n", + " \"price\": 18.5,\n", + " \"category\": \"bowls\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\",\n", + " \"gluten-free\"\n", + " ]\n", " },\n", " {\n", - " \"id\": 5,\n", - " \"name\": \"Louvre Museum\",\n", - " \"description\": \"World's largest art museum and historic monument in Paris\",\n", - " \"category\": \"museums\",\n", - " \"location\": {\n", - " \"city\": \"Paris\",\n", - " \"country\": \"France\",\n", - " \"region\": \"Île-de-France\",\n", - " \"coordinates\": null\n", - " },\n", - " \"rating\": 4.4,\n", - " \"image_url\": \"https://example.com/louvre.jpg\",\n", - " \"website\": \"https://www.louvre.fr\",\n", - " \"opening_hours\": \"9:00 AM - 6:00 PM\",\n", - " \"entry_fee\": \"€17\"\n", + " \"id\": \"item_rest_101_002\",\n", + " \"name\": \"Grilled Salmon Salad\",\n", + " \"description\": \"Fresh salmon over mixed greens with lemon vinaigrette\",\n", + " \"price\": 24.0,\n", + " \"category\": \"salads\",\n", + " \"dietary_info\": [\n", + " \"pescatarian\",\n", + " \"keto-friendly\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_101_003\",\n", + " \"name\": \"Green Smoothie\",\n", + " \"description\": \"Spinach, banana, mango, and coconut water\",\n", + " \"price\": 8.5,\n", + " \"category\": \"beverages\",\n", + " \"dietary_info\": [\n", + " \"vegan\",\n", + " \"raw\"\n", + " ]\n", " }\n", " ]\n", - "}\u001b[0m\u001b[32;1m\u001b[1;3mGreat — here are popular Paris attractions with quick notes and tips. Tell me which ones you want more details or to book.\n", - "\n", - "- Eiffel Tower (architecture) — Iconic iron tower on the Champ de Mars. Opening hours: ~9:30 AM–11:45 PM. Tickets range ~€29–€73 depending on access/age. Tip: book a timed-entry or summit ticket in advance; sunset or night views are spectacular.\n", - "\n", - "- Louvre Museum (museums) — World’s largest art museum (home of the Mona Lisa). Opening hours: ~9:00 AM–6:00 PM; entry ~€17. Tip: closed some weekdays (check before you go), use a timed-entry ticket and allow 2–4 hours (or more).\n", - "\n", - "Other top picks to consider:\n", - "- Notre‑Dame Cathedral (historic landmark) — note: restoration work continues after the 2019 fire; access may be limited.\n", - "- Musée d’Orsay — Impressionist and post‑Impressionist masterpieces in a former railway station.\n", - "- Sacré‑Cœur and Montmartre — hilltop basilica with great city views and a bohemian neighborhood to explore.\n", - "- Arc de Triomphe & Champs‑Élysées — climb the Arc for views; stroll the avenue for shopping and cafés.\n", - "- Sainte‑Chapelle — stunning medieval stained-glass chapel on Île de la Cité.\n", - "- Seine river cruise (Bateaux Mouches or similar) — relaxing way to see many riverside monuments.\n", - "- Luxembourg Gardens — peaceful park for a stroll or picnic.\n", - "- Palace of Versailles (day trip) — lavish palace and gardens just outside Paris; allow a full day.\n", + "}\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + " \"restaurant_id\": \"rest_103\",\n", + " \"restaurant_name\": \"Sushi Central\",\n", + " \"menu_items\": [\n", + " {\n", + " \"id\": \"item_rest_103_001\",\n", + " \"name\": \"Omakase Tasting Menu\",\n", + " \"description\": \"Chef's selection of 12 pieces of premium sushi\",\n", + " \"price\": 85.0,\n", + " \"category\": \"tasting_menu\",\n", + " \"dietary_info\": [\n", + " \"pescatarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_103_002\",\n", + " \"name\": \"Dragon Roll\",\n", + " \"description\": \"Eel, cucumber, topped with avocado and eel sauce\",\n", + " \"price\": 18.5,\n", + " \"category\": \"specialty_rolls\",\n", + " \"dietary_info\": [\n", + " \"pescatarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_103_003\",\n", + " \"name\": \"Miso Soup\",\n", + " \"description\": \"Traditional soybean paste soup with tofu and seaweed\",\n", + " \"price\": 6.0,\n", + " \"category\": \"appetizers\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\",\n", + " \"vegan\"\n", + " ]\n", + " }\n", + " ]\n", + "}\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + " \"restaurant_id\": \"rest_105\",\n", + " \"restaurant_name\": \"Taco Town\",\n", + " \"menu_items\": [\n", + " {\n", + " \"id\": \"item_rest_105_001\",\n", + " \"name\": \"Carnitas Tacos\",\n", + " \"description\": \"Slow-cooked pork with onions, cilantro, and lime\",\n", + " \"price\": 11.5,\n", + " \"category\": \"tacos\",\n", + " \"dietary_info\": []\n", + " },\n", + " {\n", + " \"id\": \"item_rest_105_002\",\n", + " \"name\": \"Vegetarian Burrito Bowl\",\n", + " \"description\": \"Black beans, rice, peppers, guac, and cheese\",\n", + " \"price\": 13.0,\n", + " \"category\": \"bowls\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_105_003\",\n", + " \"name\": \"Horchata\",\n", + " \"description\": \"Traditional rice and cinnamon drink\",\n", + " \"price\": 4.5,\n", + " \"category\": \"beverages\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " }\n", + " ]\n", + "}\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + " \"restaurant_id\": \"rest_102\",\n", + " \"restaurant_name\": \"Pizza Palace\",\n", + " \"menu_items\": [\n", + " {\n", + " \"id\": \"item_rest_102_001\",\n", + " \"name\": \"Margherita Pizza\",\n", + " \"description\": \"Classic tomato, mozzarella, and fresh basil\",\n", + " \"price\": 16.0,\n", + " \"category\": \"pizza\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_102_002\",\n", + " \"name\": \"Pepperoni Supreme\",\n", + " \"description\": \"Pepperoni, mushrooms, bell peppers, and extra cheese\",\n", + " \"price\": 19.5,\n", + " \"category\": \"pizza\",\n", + " \"dietary_info\": []\n", + " },\n", + " {\n", + " \"id\": \"item_rest_102_003\",\n", + " \"name\": \"Caesar Salad\",\n", + " \"description\": \"Romaine lettuce, parmesan, croutons, and Caesar dressing\",\n", + " \"price\": 12.0,\n", + " \"category\": \"salads\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " }\n", + " ]\n", + "}\u001b[0m\u001b[32;1m\u001b[1;3mHere are the New York restaurants from the search, with gluten-free options noted from their menus:\n", "\n", - "Would you like:\n", - "- Details for any specific attraction (hours, accessibility, guided tours)?\n", - "- Help booking tickets (tell me date, number of visitors, name/email)?\n", - "- Current weather for Paris right now or a forecast for your travel dates?\u001b[0m\n", + "- Green Bowl (id rest_101) – healthy\n", + " - Gluten-free option: Quinoa Power Bowl (gluten-free)\n", + " - Other items: Grilled Salmon Salad, Green Smoothie (no gluten-free tag)\n", "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "Great — here are popular Paris attractions with quick notes and tips. Tell me which ones you want more details or to book.\n", - "\n", - "- Eiffel Tower (architecture) — Iconic iron tower on the Champ de Mars. Opening hours: ~9:30 AM–11:45 PM. Tickets range ~€29–€73 depending on access/age. Tip: book a timed-entry or summit ticket in advance; sunset or night views are spectacular.\n", - "\n", - "- Louvre Museum (museums) — World’s largest art museum (home of the Mona Lisa). Opening hours: ~9:00 AM–6:00 PM; entry ~€17. Tip: closed some weekdays (check before you go), use a timed-entry ticket and allow 2–4 hours (or more).\n", - "\n", - "Other top picks to consider:\n", - "- Notre‑Dame Cathedral (historic landmark) — note: restoration work continues after the 2019 fire; access may be limited.\n", - "- Musée d’Orsay — Impressionist and post‑Impressionist masterpieces in a former railway station.\n", - "- Sacré‑Cœur and Montmartre — hilltop basilica with great city views and a bohemian neighborhood to explore.\n", - "- Arc de Triomphe & Champs‑Élysées — climb the Arc for views; stroll the avenue for shopping and cafés.\n", - "- Sainte‑Chapelle — stunning medieval stained-glass chapel on Île de la Cité.\n", - "- Seine river cruise (Bateaux Mouches or similar) — relaxing way to see many riverside monuments.\n", - "- Luxembourg Gardens — peaceful park for a stroll or picnic.\n", - "- Palace of Versailles (day trip) — lavish palace and gardens just outside Paris; allow a full day.\n", - "\n", - "Would you like:\n", - "- Details for any specific attraction (hours, accessibility, guided tours)?\n", - "- Help booking tickets (tell me date, number of visitors, name/email)?\n", - "- Current weather for Paris right now or a forecast for your travel dates?\n", - "🧳 User: book eiffel tower\n", - "🤖 Assistant:\n", + "- Pizza Palace (id rest_102) – italian\n", + " - Gluten-free options: none tagged\n", + " - Menu highlights: Margherita Pizza, Pepperoni Supreme, Caesar Salad (caesar has croutons)\n", "\n", + "- Sushi Central (id rest_103) – japanese\n", + " - Gluten-free options: none tagged\n", + " - Menu highlights: Omakase Tasting Menu, Dragon Roll, Miso Soup (vegetarian/vegan; gluten-free not indicated)\n", "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `search_attractions` with `{'location': 'Paris', 'category': 'architecture', 'limit': 20}`\n", + "- Taco Town (id rest_105) – mexican\n", + " - Gluten-free options: none tagged\n", + " - Menu highlights: Carnitas Tacos, Vegetarian Burrito Bowl, Horchata\n", "\n", + "If you want, I can drill down further on any item or find more gluten-free options in New York.\u001b[0m\n", "\n", - "\u001b[0m\u001b[33;1m\u001b[1;3m{\n", - " \"category\": \"Architecture\",\n", - " \"location\": \"Paris\",\n", - " \"total_count\": 1,\n", - " \"attractions\": [\n", - " {\n", - " \"id\": 1,\n", - " \"name\": \"Eiffel Tower\",\n", - " \"description\": \"Iconic iron lattice tower located on the Champ de Mars in Paris, France\",\n", - " \"category\": \"architecture\",\n", - " \"location\": {\n", - " \"city\": \"Paris\",\n", - " \"country\": \"France\",\n", - " \"region\": \"Île-de-France\",\n", - " \"coordinates\": null\n", - " },\n", - " \"rating\": 4.6,\n", - " \"image_url\": \"https://example.com/eiffel-tower.jpg\",\n", - " \"website\": \"https://www.toureiffel.paris\",\n", - " \"opening_hours\": \"9:30 AM - 11:45 PM\",\n", - " \"entry_fee\": \"€29.40 - €73.30\"\n", - " }\n", - " ]\n", - "}\u001b[0m\u001b[32;1m\u001b[1;3mI can book the Eiffel Tower for you — I just need a few details first:\n", + "\u001b[1m> Finished chain.\u001b[0m\n", + "Here are the New York restaurants from the search, with gluten-free options noted from their menus:\n", "\n", - "1) Visit date (YYYY-MM-DD) \n", - "2) Number of visitors (1–50) \n", - "3) Primary visitor name (for the booking) \n", - "4) Email for confirmation \n", - "5) Phone number (optional) \n", - "6) Any special requests or ticket preference (e.g., summit access vs 2nd floor only, stairs vs elevator, preferred time window like morning/afternoon/evening)\n", + "- Green Bowl (id rest_101) – healthy\n", + " - Gluten-free option: Quinoa Power Bowl (gluten-free)\n", + " - Other items: Grilled Salmon Salad, Green Smoothie (no gluten-free tag)\n", "\n", - "Tell me those and I’ll proceed to check availability and make the booking. Would you also like me to include current weather for Paris on your visit date?\u001b[0m\n", + "- Pizza Palace (id rest_102) – italian\n", + " - Gluten-free options: none tagged\n", + " - Menu highlights: Margherita Pizza, Pepperoni Supreme, Caesar Salad (caesar has croutons)\n", "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "I can book the Eiffel Tower for you — I just need a few details first:\n", + "- Sushi Central (id rest_103) – japanese\n", + " - Gluten-free options: none tagged\n", + " - Menu highlights: Omakase Tasting Menu, Dragon Roll, Miso Soup (vegetarian/vegan; gluten-free not indicated)\n", "\n", - "1) Visit date (YYYY-MM-DD) \n", - "2) Number of visitors (1–50) \n", - "3) Primary visitor name (for the booking) \n", - "4) Email for confirmation \n", - "5) Phone number (optional) \n", - "6) Any special requests or ticket preference (e.g., summit access vs 2nd floor only, stairs vs elevator, preferred time window like morning/afternoon/evening)\n", + "- Taco Town (id rest_105) – mexican\n", + " - Gluten-free options: none tagged\n", + " - Menu highlights: Carnitas Tacos, Vegetarian Burrito Bowl, Horchata\n", "\n", - "Tell me those and I’ll proceed to check availability and make the booking. Would you also like me to include current weather for Paris on your visit date?\n", - "🧳 User: 1992-04-2992\n", + "If you want, I can drill down further on any item or find more gluten-free options in New York.\n", + "🧳 User: find restaurants with dishes that are explicitly labelled as gluten free\n", "🤖 Assistant:\n", "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3mThe date you sent looks invalid: \"1992-04-2992\" — it has extra characters and/or is in the past. I can’t book a past date. Could you please confirm the booking details using this form?\n", + "\u001b[32;1m\u001b[1;3m\n", + "Invoking: `search_restaurants` with `{'location': 'New York'}`\n", "\n", - "1) Visit date (YYYY-MM-DD) — must be a future date \n", - "2) Number of visitors (1–50) \n", - "3) Primary visitor name \n", - "4) Email for confirmation \n", - "5) Phone (optional) \n", - "6) Ticket preference / special requests (e.g., summit access vs 2nd floor only; stairs vs elevator; preferred time of day)\n", "\n", - "If you want, type everything in one line (for example):\n", - "2025-10-15, 2, Alex Martin, alex@example.com, +33-6-12-34-56-78, summit ticket, evening\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m['{\\n \"id\": \"rest_101\",\\n \"name\": \"Green Bowl\",\\n \"cuisine\": \"healthy\",\\n \"location\": \"New York\",\\n \"average_price\": 25.0,\\n \"rating\": 4.2,\\n \"opens_at\": 700,\\n \"closes_at\": 2100\\n}', '{\\n \"id\": \"rest_102\",\\n \"name\": \"Pizza Palace\",\\n \"cuisine\": \"italian\",\\n \"location\": \"New York\",\\n \"average_price\": 15.0,\\n \"rating\": 3.8,\\n \"opens_at\": 700,\\n \"closes_at\": 2300\\n}', '{\\n \"id\": \"rest_103\",\\n \"name\": \"Sushi Central\",\\n \"cuisine\": \"japanese\",\\n \"location\": \"New York\",\\n \"average_price\": 65.0,\\n \"rating\": 4.6,\\n \"opens_at\": 1700,\\n \"closes_at\": 2200\\n}', '{\\n \"id\": \"rest_105\",\\n \"name\": \"Taco Town\",\\n \"cuisine\": \"mexican\",\\n \"location\": \"New York\",\\n \"average_price\": 12.0,\\n \"rating\": 4.3,\\n \"opens_at\": 1100,\\n \"closes_at\": 2200\\n}']\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_103'}`\n", "\n", - "Tell me the corrected details and I’ll check availability and proceed. Would you also like the weather forecast for your visit date?\u001b[0m\n", "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "The date you sent looks invalid: \"1992-04-2992\" — it has extra characters and/or is in the past. I can’t book a past date. Could you please confirm the booking details using this form?\n", + "\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_102'}`\n", "\n", - "1) Visit date (YYYY-MM-DD) — must be a future date \n", - "2) Number of visitors (1–50) \n", - "3) Primary visitor name \n", - "4) Email for confirmation \n", - "5) Phone (optional) \n", - "6) Ticket preference / special requests (e.g., summit access vs 2nd floor only; stairs vs elevator; preferred time of day)\n", "\n", - "If you want, type everything in one line (for example):\n", - "2025-10-15, 2, Alex Martin, alex@example.com, +33-6-12-34-56-78, summit ticket, evening\n", + "\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_101'}`\n", "\n", - "Tell me the corrected details and I’ll check availability and proceed. Would you also like the weather forecast for your visit date?\n", - "🧳 User: escape\n", - "🤖 Assistant:\n", "\n", + "\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `get_menu` with `{'restaurant_id': 'rest_105'}`\n", "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3mDo you mean one of the following?\n", "\n", - "1) Cancel/stop the Eiffel Tower booking process (I’ll drop it and we won’t book). \n", - "2) “Escape rooms” in Paris (I can find and book an escape-room experience). \n", - "3) A short getaway/day‑trip from Paris (ideas like Versailles, Giverny, Fontainebleau). \n", - "4) Something else — please tell me what you mean.\n", + "\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + " \"restaurant_id\": \"rest_101\",\n", + " \"restaurant_name\": \"Green Bowl\",\n", + " \"menu_items\": [\n", + " {\n", + " \"id\": \"item_rest_101_001\",\n", + " \"name\": \"Quinoa Power Bowl\",\n", + " \"description\": \"Quinoa, kale, avocado, chickpeas, and tahini dressing\",\n", + " \"price\": 18.5,\n", + " \"category\": \"bowls\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\",\n", + " \"gluten-free\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_101_002\",\n", + " \"name\": \"Grilled Salmon Salad\",\n", + " \"description\": \"Fresh salmon over mixed greens with lemon vinaigrette\",\n", + " \"price\": 24.0,\n", + " \"category\": \"salads\",\n", + " \"dietary_info\": [\n", + " \"pescatarian\",\n", + " \"keto-friendly\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_101_003\",\n", + " \"name\": \"Green Smoothie\",\n", + " \"description\": \"Spinach, banana, mango, and coconut water\",\n", + " \"price\": 8.5,\n", + " \"category\": \"beverages\",\n", + " \"dietary_info\": [\n", + " \"vegan\",\n", + " \"raw\"\n", + " ]\n", + " }\n", + " ]\n", + "}\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + " \"restaurant_id\": \"rest_102\",\n", + " \"restaurant_name\": \"Pizza Palace\",\n", + " \"menu_items\": [\n", + " {\n", + " \"id\": \"item_rest_102_001\",\n", + " \"name\": \"Margherita Pizza\",\n", + " \"description\": \"Classic tomato, mozzarella, and fresh basil\",\n", + " \"price\": 16.0,\n", + " \"category\": \"pizza\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_102_002\",\n", + " \"name\": \"Pepperoni Supreme\",\n", + " \"description\": \"Pepperoni, mushrooms, bell peppers, and extra cheese\",\n", + " \"price\": 19.5,\n", + " \"category\": \"pizza\",\n", + " \"dietary_info\": []\n", + " },\n", + " {\n", + " \"id\": \"item_rest_102_003\",\n", + " \"name\": \"Caesar Salad\",\n", + " \"description\": \"Romaine lettuce, parmesan, croutons, and Caesar dressing\",\n", + " \"price\": 12.0,\n", + " \"category\": \"salads\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " }\n", + " ]\n", + "}\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + " \"restaurant_id\": \"rest_105\",\n", + " \"restaurant_name\": \"Taco Town\",\n", + " \"menu_items\": [\n", + " {\n", + " \"id\": \"item_rest_105_001\",\n", + " \"name\": \"Carnitas Tacos\",\n", + " \"description\": \"Slow-cooked pork with onions, cilantro, and lime\",\n", + " \"price\": 11.5,\n", + " \"category\": \"tacos\",\n", + " \"dietary_info\": []\n", + " },\n", + " {\n", + " \"id\": \"item_rest_105_002\",\n", + " \"name\": \"Vegetarian Burrito Bowl\",\n", + " \"description\": \"Black beans, rice, peppers, guac, and cheese\",\n", + " \"price\": 13.0,\n", + " \"category\": \"bowls\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_105_003\",\n", + " \"name\": \"Horchata\",\n", + " \"description\": \"Traditional rice and cinnamon drink\",\n", + " \"price\": 4.5,\n", + " \"category\": \"beverages\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\"\n", + " ]\n", + " }\n", + " ]\n", + "}\u001b[0m\u001b[33;1m\u001b[1;3m{\n", + " \"restaurant_id\": \"rest_103\",\n", + " \"restaurant_name\": \"Sushi Central\",\n", + " \"menu_items\": [\n", + " {\n", + " \"id\": \"item_rest_103_001\",\n", + " \"name\": \"Omakase Tasting Menu\",\n", + " \"description\": \"Chef's selection of 12 pieces of premium sushi\",\n", + " \"price\": 85.0,\n", + " \"category\": \"tasting_menu\",\n", + " \"dietary_info\": [\n", + " \"pescatarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_103_002\",\n", + " \"name\": \"Dragon Roll\",\n", + " \"description\": \"Eel, cucumber, topped with avocado and eel sauce\",\n", + " \"price\": 18.5,\n", + " \"category\": \"specialty_rolls\",\n", + " \"dietary_info\": [\n", + " \"pescatarian\"\n", + " ]\n", + " },\n", + " {\n", + " \"id\": \"item_rest_103_003\",\n", + " \"name\": \"Miso Soup\",\n", + " \"description\": \"Traditional soybean paste soup with tofu and seaweed\",\n", + " \"price\": 6.0,\n", + " \"category\": \"appetizers\",\n", + " \"dietary_info\": [\n", + " \"vegetarian\",\n", + " \"vegan\"\n", + " ]\n", + " }\n", + " ]\n", + "}\u001b[0m\u001b[32;1m\u001b[1;3mHere are New York restaurants with dishes explicitly labeled gluten-free in their menus:\n", + "\n", + "- Green Bowl (rest_101)\n", + " - Quinoa Power Bowl — gluten-free\n", + " - Price: 18.5\n", + " - Description: Quinoa, kale, avocado, chickpeas, and tahini dressing\n", "\n", - "Reply with the option number (or explain) and I’ll proceed.\u001b[0m\n", + "Other NY restaurants in the list do not have items explicitly labeled gluten-free in their current menus. If you’d like, I can widen the search to more places or check for gluten-free labels in other cities.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", - "Do you mean one of the following?\n", + "Here are New York restaurants with dishes explicitly labeled gluten-free in their menus:\n", "\n", - "1) Cancel/stop the Eiffel Tower booking process (I’ll drop it and we won’t book). \n", - "2) “Escape rooms” in Paris (I can find and book an escape-room experience). \n", - "3) A short getaway/day‑trip from Paris (ideas like Versailles, Giverny, Fontainebleau). \n", - "4) Something else — please tell me what you mean.\n", + "- Green Bowl (rest_101)\n", + " - Quinoa Power Bowl — gluten-free\n", + " - Price: 18.5\n", + " - Description: Quinoa, kale, avocado, chickpeas, and tahini dressing\n", "\n", - "Reply with the option number (or explain) and I’ll proceed.\n", + "Other NY restaurants in the list do not have items explicitly labeled gluten-free in their current menus. If you’d like, I can widen the search to more places or check for gluten-free labels in other cities.\n", "Goodbye!\n" ] } @@ -890,7 +951,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 120, "id": "968731b7", "metadata": {}, "outputs": [ @@ -935,7 +996,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.3" + "version": "3.13.7" } }, "nbformat": 4, diff --git a/src/mcp/restaurants-mcp/.python-version b/src/mcp/restaurants-mcp/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/src/mcp/restaurants-mcp/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/src/mcp/restaurants-mcp/README.md b/src/mcp/restaurants-mcp/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/mcp/restaurants-mcp/config.py b/src/mcp/restaurants-mcp/config.py new file mode 100644 index 0000000..6113b65 --- /dev/null +++ b/src/mcp/restaurants-mcp/config.py @@ -0,0 +1,405 @@ +MOCK_RESTAURANTS = [ + { + "id": "rest_101", + "name": "Green Bowl", + "cuisine": "healthy", + "location": "New York", + "average_price": 25.0, + "rating": 4.2, + "opens_at": 700, + "closes_at": 2100 + }, + { + "id": "rest_102", + "name": "Pizza Palace", + "cuisine": "italian", + "location": "New York", + "average_price": 15.0, + "rating": 3.8, + "opens_at": 700, + "closes_at": 2300 + }, + { + "id": "rest_103", + "name": "Sushi Central", + "cuisine": "japanese", + "location": "New York", + "average_price": 65.0, + "rating": 4.6, + "opens_at": 1700, + "closes_at": 2200 + }, + { + "id": "rest_104", + "name": "Burger Haven", + "cuisine": "american", + "location": "Chicago", + "average_price": 18.0, + "rating": 4.1, + "opens_at": 1000, + "closes_at": 2400 + }, + { + "id": "rest_105", + "name": "Taco Town", + "cuisine": "mexican", + "location": "New York", + "average_price": 12.0, + "rating": 4.3, + "opens_at": 1100, + "closes_at": 2200 + }, + { + "id": "rest_106", + "name": "Pasta Point", + "cuisine": "italian", + "location": "Chicago", + "average_price": 28.0, + "rating": 3.9, + "opens_at": 1600, + "closes_at": 2200 + }, + { + "id": "rest_107", + "name": "Curry Corner", + "cuisine": "indian", + "location": "Chicago", + "average_price": 22.0, + "rating": 4.4, + "opens_at": 1200, + "closes_at": 2200 + }, + { + "id": "rest_108", + "name": "BBQ Barn", + "cuisine": "american", + "location": "Chicago", + "average_price": 45.0, + "rating": 4.7, + "opens_at": 1600, + "closes_at": 2300 + }, + { + "id": "rest_109", + "name": "Falafel Factory", + "cuisine": "mediterranean", + "location": "Seattle", + "average_price": 14.0, + "rating": 4.0, + "opens_at": 1000, + "closes_at": 2100 + }, + { + "id": "rest_110", + "name": "Noodle Nest", + "cuisine": "asian", + "location": "Seattle", + "average_price": 20.0, + "rating": 3.7, + "opens_at": 1130, + "closes_at": 2230 + } +] + +MOCK_MENUS = [ + { + "restaurant_id": "rest_101", + "restaurant_name": "Green Bowl", + "menu_items": [ + { + "id": "item_rest_101_001", + "name": "Quinoa Power Bowl", + "description": "Quinoa, kale, avocado, chickpeas, and tahini dressing", + "price": 18.50, + "category": "bowls", + "dietary_info": ["vegetarian", "gluten-free"] + }, + { + "id": "item_rest_101_002", + "name": "Grilled Salmon Salad", + "description": "Fresh salmon over mixed greens with lemon vinaigrette", + "price": 24.00, + "category": "salads", + "dietary_info": ["pescatarian", "keto-friendly"] + }, + { + "id": "item_rest_101_003", + "name": "Green Smoothie", + "description": "Spinach, banana, mango, and coconut water", + "price": 8.50, + "category": "beverages", + "dietary_info": ["vegan", "raw"] + } + ] + }, + { + "restaurant_id": "rest_102", + "restaurant_name": "Pizza Palace", + "menu_items": [ + { + "id": "item_rest_102_001", + "name": "Margherita Pizza", + "description": "Classic tomato, mozzarella, and fresh basil", + "price": 16.00, + "category": "pizza", + "dietary_info": ["vegetarian"] + }, + { + "id": "item_rest_102_002", + "name": "Pepperoni Supreme", + "description": "Pepperoni, mushrooms, bell peppers, and extra cheese", + "price": 19.50, + "category": "pizza", + "dietary_info": [] + }, + { + "id": "item_rest_102_003", + "name": "Caesar Salad", + "description": "Romaine lettuce, parmesan, croutons, and Caesar dressing", + "price": 12.00, + "category": "salads", + "dietary_info": ["vegetarian"] + } + ] + }, + { + "restaurant_id": "rest_103", + "restaurant_name": "Sushi Central", + "menu_items": [ + { + "id": "item_rest_103_001", + "name": "Omakase Tasting Menu", + "description": "Chef's selection of 12 pieces of premium sushi", + "price": 85.00, + "category": "tasting_menu", + "dietary_info": ["pescatarian"] + }, + { + "id": "item_rest_103_002", + "name": "Dragon Roll", + "description": "Eel, cucumber, topped with avocado and eel sauce", + "price": 18.50, + "category": "specialty_rolls", + "dietary_info": ["pescatarian"] + }, + { + "id": "item_rest_103_003", + "name": "Miso Soup", + "description": "Traditional soybean paste soup with tofu and seaweed", + "price": 6.00, + "category": "appetizers", + "dietary_info": ["vegetarian", "vegan"] + } + ] + }, + { + "restaurant_id": "rest_104", + "restaurant_name": "Burger Haven", + "menu_items": [ + { + "id": "item_rest_104_001", + "name": "Classic Cheeseburger", + "description": "Beef patty, cheese, lettuce, tomato, onion, and pickles", + "price": 16.50, + "category": "burgers", + "dietary_info": [] + }, + { + "id": "item_rest_104_002", + "name": "Truffle Fries", + "description": "Hand-cut fries with truffle oil and parmesan", + "price": 12.00, + "category": "sides", + "dietary_info": ["vegetarian"] + }, + { + "id": "item_rest_104_003", + "name": "Chocolate Milkshake", + "description": "Rich chocolate shake topped with whipped cream", + "price": 8.50, + "category": "beverages", + "dietary_info": ["vegetarian"] + } + ] + }, + { + "restaurant_id": "rest_105", + "restaurant_name": "Taco Town", + "menu_items": [ + { + "id": "item_rest_105_001", + "name": "Carnitas Tacos", + "description": "Slow-cooked pork with onions, cilantro, and lime", + "price": 11.50, + "category": "tacos", + "dietary_info": [] + }, + { + "id": "item_rest_105_002", + "name": "Vegetarian Burrito Bowl", + "description": "Black beans, rice, peppers, guac, and cheese", + "price": 13.00, + "category": "bowls", + "dietary_info": ["vegetarian"] + }, + { + "id": "item_rest_105_003", + "name": "Horchata", + "description": "Traditional rice and cinnamon drink", + "price": 4.50, + "category": "beverages", + "dietary_info": ["vegetarian"] + } + ] + }, + { + "restaurant_id": "rest_106", + "restaurant_name": "Pasta Point", + "menu_items": [ + { + "id": "item_rest_106_001", + "name": "Fettuccine Alfredo", + "description": "Creamy alfredo sauce with fresh fettuccine pasta", + "price": 22.00, + "category": "pasta", + "dietary_info": ["vegetarian"] + }, + { + "id": "item_rest_106_002", + "name": "Chicken Parmigiana", + "description": "Breaded chicken breast with marinara and mozzarella", + "price": 28.50, + "category": "entrees", + "dietary_info": [] + }, + { + "id": "item_rest_106_003", + "name": "Tiramisu", + "description": "Classic Italian dessert with coffee and mascarpone", + "price": 9.00, + "category": "desserts", + "dietary_info": ["vegetarian"] + } + ] + }, + { + "restaurant_id": "rest_107", + "restaurant_name": "Curry Corner", + "menu_items": [ + { + "id": "item_rest_107_001", + "name": "Butter Chicken", + "description": "Tender chicken in creamy tomato-based curry sauce", + "price": 19.50, + "category": "curries", + "dietary_info": [] + }, + { + "id": "item_rest_107_002", + "name": "Vegetable Biryani", + "description": "Fragrant basmati rice with mixed vegetables and spices", + "price": 16.00, + "category": "rice_dishes", + "dietary_info": ["vegetarian", "vegan"] + }, + { + "id": "item_rest_107_003", + "name": "Garlic Naan", + "description": "Fresh baked bread with garlic and cilantro", + "price": 4.50, + "category": "breads", + "dietary_info": ["vegetarian"] + } + ] + }, + { + "restaurant_id": "rest_108", + "restaurant_name": "BBQ Barn", + "menu_items": [ + { + "id": "item_rest_108_001", + "name": "Smoked Brisket Platter", + "description": "12-hour smoked brisket with coleslaw and cornbread", + "price": 32.00, + "category": "bbq_platters", + "dietary_info": [] + }, + { + "id": "item_rest_108_002", + "name": "Pulled Pork Sandwich", + "description": "Slow-smoked pork with BBQ sauce on brioche bun", + "price": 18.50, + "category": "sandwiches", + "dietary_info": [] + }, + { + "id": "item_rest_108_003", + "name": "Mac and Cheese", + "description": "Creamy three-cheese mac with bacon crumbles", + "price": 14.00, + "category": "sides", + "dietary_info": ["vegetarian"] + } + ] + }, + { + "restaurant_id": "rest_109", + "restaurant_name": "Falafel Factory", + "menu_items": [ + { + "id": "item_rest_109_001", + "name": "Falafel Wrap", + "description": "Crispy falafel with hummus, tahini, and fresh vegetables", + "price": 12.50, + "category": "wraps", + "dietary_info": ["vegetarian", "vegan"] + }, + { + "id": "item_rest_109_002", + "name": "Mediterranean Platter", + "description": "Hummus, baba ganoush, olives, and pita bread", + "price": 16.00, + "category": "platters", + "dietary_info": ["vegetarian", "vegan"] + }, + { + "id": "item_rest_109_003", + "name": "Baklava", + "description": "Flaky phyllo pastry with honey and pistachios", + "price": 6.50, + "category": "desserts", + "dietary_info": ["vegetarian"] + } + ] + }, + { + "restaurant_id": "rest_110", + "restaurant_name": "Noodle Nest", + "menu_items": [ + { + "id": "item_rest_110_001", + "name": "Pad Thai", + "description": "Stir-fried rice noodles with shrimp, tofu, and peanuts", + "price": 17.50, + "category": "noodles", + "dietary_info": ["pescatarian"] + }, + { + "id": "item_rest_110_002", + "name": "Ramen Bowl", + "description": "Rich pork broth with fresh noodles and soft-boiled egg", + "price": 21.00, + "category": "soups", + "dietary_info": [] + }, + { + "id": "item_rest_110_003", + "name": "Spring Rolls", + "description": "Fresh vegetables wrapped in rice paper with peanut sauce", + "price": 8.50, + "category": "appetizers", + "dietary_info": ["vegetarian", "vegan"] + } + ] + } +] \ No newline at end of file diff --git a/src/mcp/restaurants-mcp/main.py b/src/mcp/restaurants-mcp/main.py new file mode 100644 index 0000000..4a5718d --- /dev/null +++ b/src/mcp/restaurants-mcp/main.py @@ -0,0 +1,83 @@ +""" +Restaurant MCP Server + +A Model Context Protocol (MCP) server that provides restaurant search and menu functionality. + +Features: +- Search restaurants by cuisine, location, price, and rating +- Get detailed restaurant information +- Access restaurant menus with dietary information + +Available Tools: +- search_restaurants: Find restaurants with optional filters +- get_restaurant_details: Get specific restaurant information +- get_menu: Retrieve restaurant menu (MCP resource) + +To run this server: + uv run mcp dev main.py + +The server runs on port 8010 with streamable HTTP transport. +""" + +from mcp.server.fastmcp import FastMCP + +from typing import Any, Dict, List, Optional +from restaurant_service import ( + search_restaurants as search_restaurants_service, + get_restaurant_menu, +) + +mcp = FastMCP("Restaurants", port=8010) + + +@mcp.tool() +def search_restaurants( + cuisine: Optional[str] = None, + location: Optional[str] = None, + average_price: Optional[float] = None, + rating_min: Optional[float] = None, + opens_at: Optional[int] = None, + closes_at: Optional[int] = None, +) -> List[Dict[str, Any]]: + """Search for restaurants with optional filters + + Args: + cuisine: Filter by cuisine type (e.g. "italian", "chinese") + location: City name or place name (e.g., "London", "New York", "Tokyo") + average_price: Filter by maximum average price per person (e.g. 50) + rating_min: Minimum rating filter (e.g., 4) + opens_at: Filter by opening hours (e.g. 700) + closes_at: Filter by closing hours (e.g. 2100) + + Returns: + RestaurantsList object as dictionary with matching restaurants + """ + return search_restaurants_service( + cuisine, + location, + average_price, + rating_min, + opens_at, + closes_at, + ) + + +@mcp.tool() +def get_menu(restaurant_id: str) -> Dict[str, Any]: + """Get menu for a specific restaurant + + Args: + restaurant_id: The ID of the restaurant to get menu for + + Returns: + Menu data for the restaurant + """ + menu = get_restaurant_menu(restaurant_id) + if menu: + return menu + else: + return {"error": f"Restaurant not found"} + + +if __name__ == "__main__": + mcp.run(transport="streamable-http") diff --git a/src/mcp/restaurants-mcp/models.py b/src/mcp/restaurants-mcp/models.py new file mode 100644 index 0000000..dd9eef5 --- /dev/null +++ b/src/mcp/restaurants-mcp/models.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass +from typing import Any, Optional, List + + +@dataclass +class RestaurantsList: + category: str + location: Optional[str] = None + total_count: int = 0 + restaurants: List[Any] = None \ No newline at end of file diff --git a/src/mcp/restaurants-mcp/pyproject.toml b/src/mcp/restaurants-mcp/pyproject.toml new file mode 100644 index 0000000..cfa2762 --- /dev/null +++ b/src/mcp/restaurants-mcp/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "restaurants-mcp" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "mcp[cli]>=1.14.1", +] diff --git a/src/mcp/restaurants-mcp/restaurant_service.py b/src/mcp/restaurants-mcp/restaurant_service.py new file mode 100644 index 0000000..2b2406b --- /dev/null +++ b/src/mcp/restaurants-mcp/restaurant_service.py @@ -0,0 +1,100 @@ +""" +Restaurant Service + +Handles all restaurant-related business logic and data operations. +""" + +from typing import Any, Dict, List, Optional +from config import MOCK_RESTAURANTS, MOCK_MENUS + + +def search_restaurants( + cuisine: Optional[str] = None, + location: Optional[str] = None, + average_price: Optional[float] = None, + rating_min: Optional[float] = None, + opens_at: Optional[int] = None, + closes_at: Optional[int] = None +) -> List[Dict[str, Any]]: + + filtered_restaurants = MOCK_RESTAURANTS.copy() + + # Apply filters if provided + if cuisine: + filtered_restaurants = [ + r for r in filtered_restaurants + if r.get("cuisine", "").lower() == cuisine.lower() + ] + + if location: + filtered_restaurants = [ + r for r in filtered_restaurants + if location.lower() in r.get("location", "").lower() + ] + + if average_price: + filtered_restaurants = [ + r for r in filtered_restaurants + if r.get("average_price", 0) <= average_price + ] + + if rating_min: + filtered_restaurants = [ + r for r in filtered_restaurants + if r.get("rating", 0) >= rating_min + ] + + if opens_at: + filtered_restaurants = [ + r for r in filtered_restaurants + if r.get("opens_at", 0) >= opens_at + ] + + if closes_at: + filtered_restaurants = [ + r for r in filtered_restaurants + if r.get("closes_at", 23) <= closes_at + ] + + return filtered_restaurants + + +def get_restaurant_by_id(restaurant_id: str) -> Optional[Dict[str, Any]]: + """Get a specific restaurant by ID + + Args: + restaurant_id: The restaurant ID to search for + + Returns: + Restaurant data if found, None otherwise + """ + for restaurant in MOCK_RESTAURANTS: + if restaurant.get("id") == restaurant_id: + return restaurant + return None + + +def get_restaurant_menu(restaurant_id: str) -> Optional[Dict[str, Any]]: + """Get menu for a specific restaurant + + Args: + restaurant_id: The restaurant ID to get menu for + + Returns: + Menu data if restaurant found, None otherwise + """ + # Check if restaurant exists first + restaurant = get_restaurant_by_id(restaurant_id) + if not restaurant: + return None + + # Return menu from config if available + return get_menu_items_by_restaurant(restaurant_id) + + +def get_menu_items_by_restaurant(restaurant_id: str) -> Dict[str, Any]: + """Get all menu items for a specific restaurant""" + for menu in MOCK_MENUS: + if menu["restaurant_id"] == restaurant_id: + return menu + return None \ No newline at end of file diff --git a/src/mcp/restaurants-mcp/uv.lock b/src/mcp/restaurants-mcp/uv.lock new file mode 100644 index 0000000..227bd15 --- /dev/null +++ b/src/mcp/restaurants-mcp/uv.lock @@ -0,0 +1,486 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/fa/66bd985dd0b7c109a3bcb89272ee0bfb7e2b4d06309ad7b38ff866734b2a/httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e", size = 12998, upload-time = "2025-06-24T13:21:05.71Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/0a/6269e3473b09aed2dab8aa1a600c70f31f00ae1349bee30658f7e358a159/httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37", size = 8054, upload-time = "2025-06-24T13:21:04.772Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "mcp" +version = "1.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/e9/242096400d702924b49f8d202c6ded7efb8841cacba826b5d2e6183aef7b/mcp-1.14.1.tar.gz", hash = "sha256:31c4406182ba15e8f30a513042719c3f0a38c615e76188ee5a736aaa89e20134", size = 454944, upload-time = "2025-09-18T13:37:19.971Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/11/d334fbb7c2aeddd2e762b86d7a619acffae012643a5738e698f975a2a9e2/mcp-1.14.1-py3-none-any.whl", hash = "sha256:3b7a479e8e5cbf5361bdc1da8bc6d500d795dc3aff44b44077a363a7f7e945a4", size = 163809, upload-time = "2025-09-18T13:37:18.165Z" }, +] + +[package.optional-dependencies] +cli = [ + { name = "python-dotenv" }, + { name = "typer" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "restaurants-mcp" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "mcp", extra = ["cli"] }, +] + +[package.metadata] +requires-dist = [{ name = "mcp", extras = ["cli"], specifier = ">=1.14.1" }] + +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" }, + { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" }, + { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" }, + { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" }, + { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" }, + { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" }, + { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, + { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, + { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, + { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, + { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, + { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, + { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, + { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, + { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, + { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, + { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, + { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/6f/22ed6e33f8a9e76ca0a412405f31abb844b779d52c5f96660766edcd737c/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a", size = 20985, upload-time = "2025-07-27T09:07:44.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/10/c78f463b4ef22eef8491f218f692be838282cd65480f6e423d7730dfd1fb/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a", size = 11297, upload-time = "2025-07-27T09:07:43.268Z" }, +] + +[[package]] +name = "starlette" +version = "0.48.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, +] + +[[package]] +name = "typer" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/ca/950278884e2ca20547ff3eb109478c6baf6b8cf219318e6bc4f666fad8e8/typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca", size = 104755, upload-time = "2025-09-23T09:47:48.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/22/35617eee79080a5d071d0f14ad698d325ee6b3bf824fc0467c03b30e7fa8/typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9", size = 46748, upload-time = "2025-09-23T09:47:46.777Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/57/1616c8274c3442d802621abf5deb230771c7a0fec9414cb6763900eb3868/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13", size = 80367, upload-time = "2025-09-23T13:33:47.486Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/cd/584a2ceb5532af99dd09e50919e3615ba99aa127e9850eafe5f31ddfdb9a/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c", size = 67976, upload-time = "2025-09-23T13:33:45.842Z" }, +]