use pydantic

This commit is contained in:
2025-12-13 04:35:40 +01:00
parent 79fc89a7f4
commit 955f992f8e
23 changed files with 1340 additions and 5363 deletions

View File

@@ -1,14 +0,0 @@
Dockerfile
.dockerignore
.git
.gitignore
.env
.env.*
.venv/
venv/
__pycache__/
*.pyc
*.pyo
.langgraph_api/
.vercel/
*.md

View File

@@ -1,9 +0,0 @@
venv/
__pycache__/
*.pyc
.env
.vercel
# python
.venv/
.langgraph_api/

View File

@@ -0,0 +1 @@
3.12

View File

@@ -1,21 +0,0 @@
# syntax=docker/dockerfile:1
FROM python:3.13-slim
WORKDIR /app
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# Copy dependency files
COPY pyproject.toml uv.lock ./
# Install dependencies
RUN uv sync --frozen --no-dev --no-install-project
# Copy application code
COPY main.py server.py ./
EXPOSE 8000
CMD ["uv", "run", "python", "server.py"]

View File

@@ -1,26 +0,0 @@
"""
PydanticAI agent with MCP tools from Cavepedia server.
"""
from pydantic_ai import Agent
from pydantic_ai.models.google import GoogleModel
from pydantic_ai.mcp import MCPServerStreamableHTTP
# Create MCP server connection to Cavepedia
mcp_server = MCPServerStreamableHTTP(
url="https://mcp.caving.dev/mcp",
timeout=30.0,
)
# Create the agent with Google Gemini model
agent = Agent(
model=GoogleModel("gemini-2.5-pro"),
toolsets=[mcp_server],
instructions="""You are a helpful assistant with access to cave-related information through the Cavepedia MCP server. You can help users find information about caves, caving techniques, and related topics.
IMPORTANT RULES:
1. Always cite your sources at the end of each response. List the specific sources/documents you used.
2. If you cannot find information on a topic, say so clearly. Do NOT make up information or hallucinate facts.
3. If the MCP tools return no results, acknowledge that you couldn't find the information rather than guessing.""",
)

View File

@@ -1,11 +1,12 @@
[project]
name = "vpi-1000"
version = "1.0.0"
description = "VPI-1000"
requires-python = ">=3.13,<3.14"
name = "agent"
version = "0.1.0"
description = "Cavepedia AI Agent with MCP tools"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"pydantic-ai>=0.1.0",
"fastapi>=0.115.5,<1.0.0",
"uvicorn>=0.29.0,<1.0.0",
"python-dotenv>=1.0.0,<2.0.0",
"uvicorn",
"pydantic-ai[google,mcp,ag-ui]",
"python-dotenv",
"logfire>=4.10.0",
]

View File

@@ -1,20 +0,0 @@
"""
Self-hosted PydanticAI agent server using AG-UI protocol.
"""
import os
import uvicorn
from dotenv import load_dotenv
from pydantic_ai.ui.ag_ui.app import AGUIApp
from main import agent
load_dotenv()
# Convert PydanticAI agent to ASGI app with AG-UI protocol
app = AGUIApp(agent)
if __name__ == "__main__":
port = int(os.getenv("PORT", "8000"))
uvicorn.run(app, host="0.0.0.0", port=port)

62
web/agent/src/agent.py Normal file
View File

@@ -0,0 +1,62 @@
"""
PydanticAI agent with MCP tools from Cavepedia server.
"""
import logging
import httpx
from pydantic_ai import Agent
from pydantic_ai.models.google import GoogleModel
# Set up logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
MCP_URL = "https://mcp.caving.dev/mcp"
logger.info("Initializing Cavepedia agent...")
def check_mcp_available(url: str, timeout: float = 5.0) -> bool:
"""Check if MCP server is reachable."""
try:
# Just check if we can connect - don't need a full MCP handshake
response = httpx.get(url, timeout=timeout, follow_redirects=True)
# Any response (even 4xx/5xx) means server is reachable
# 502 means upstream is down, so treat as unavailable
if response.status_code == 502:
logger.warning(f"MCP server returned 502 Bad Gateway")
return False
return True
except Exception as e:
logger.warning(f"MCP server not reachable: {e}")
return False
# Try to configure MCP if server is available
toolsets = []
if check_mcp_available(MCP_URL):
try:
from pydantic_ai.mcp import MCPServerStreamableHTTP
mcp_server = MCPServerStreamableHTTP(
url=MCP_URL,
timeout=30.0,
)
toolsets.append(mcp_server)
logger.info(f"MCP server configured: {MCP_URL}")
except Exception as e:
logger.warning(f"Could not configure MCP server: {e}")
else:
logger.info("MCP server unavailable - running without MCP tools")
# Create the agent with Google Gemini model
agent = Agent(
model=GoogleModel("gemini-2.5-pro"),
toolsets=toolsets if toolsets else None,
instructions="""You are a helpful caving assistant. Help users with all aspects of caving including cave exploration, safety, surveying techniques, cave locations, geology, equipment, history, conservation, and any other caving-related topics.
IMPORTANT RULES:
1. Always cite your sources at the end of each response when possible.
2. If you're not certain about information, say so clearly. Do NOT make up information or hallucinate facts.
3. Provide accurate, helpful, and safety-conscious information.""",
)
logger.info(f"Agent initialized successfully (MCP: {'enabled' if toolsets else 'disabled'})")

32
web/agent/src/main.py Normal file
View File

@@ -0,0 +1,32 @@
"""
Self-hosted PydanticAI agent server using AG-UI protocol.
"""
import os
import logging
from dotenv import load_dotenv
# Set up logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Load environment variables BEFORE importing agent
load_dotenv()
import uvicorn
from src.agent import agent
logger.info("Creating AG-UI app...")
# Convert PydanticAI agent to ASGI app with AG-UI protocol
app = agent.to_ag_ui(debug=True)
logger.info("AG-UI app created successfully")
if __name__ == "__main__":
port = int(os.getenv("PORT", "8000"))
uvicorn.run(app, host="127.0.0.1", port=port)

882
web/agent/uv.lock generated

File diff suppressed because it is too large Load Diff