tsa-shiny-agent / agent /src /tools /api_client.py
mmrech's picture
Initial deployment of TSA Shiny Agent
026774a verified
Raw
History Blame Contribute Delete
2.97 kB
"""
Plumber API Client for TSA Agent Tools
This module provides async HTTP client functionality for communicating
with the R Plumber API that bridges to the Java TSA engine.
"""
import os
import httpx
from typing import Any
def get_api_url() -> str:
"""Get the TSA API base URL from environment."""
return os.environ.get("TSA_API_URL", "http://localhost:8000")
async def api_call(
method: str,
endpoint: str,
params: dict[str, Any] | None = None,
json_data: dict[str, Any] | None = None,
timeout: float = 30.0,
) -> dict[str, Any]:
"""
Make an async API call to the Plumber API.
Args:
method: HTTP method (GET, POST, DELETE)
endpoint: API endpoint (e.g., "/analysis/create")
params: Query parameters
json_data: JSON body data
timeout: Request timeout in seconds
Returns:
API response as dictionary
"""
base_url = get_api_url()
url = f"{base_url}{endpoint}"
async with httpx.AsyncClient(timeout=timeout) as client:
try:
if method.upper() == "GET":
response = await client.get(url, params=params)
elif method.upper() == "POST":
response = await client.post(url, params=params, json=json_data)
elif method.upper() == "DELETE":
response = await client.delete(url, params=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
except httpx.ConnectError:
return {
"success": False,
"message": f"Cannot connect to TSA API at {base_url}. "
"Ensure the Plumber server is running."
}
except httpx.HTTPStatusError as e:
return {
"success": False,
"message": f"API error: {e.response.status_code} - {e.response.text}"
}
except Exception as e:
return {
"success": False,
"message": f"Unexpected error: {str(e)}"
}
def format_tool_response(
data: dict[str, Any] | str,
is_error: bool = False
) -> dict[str, Any]:
"""
Format a response for the MCP tool protocol.
Args:
data: Response data (dict or string)
is_error: Whether this is an error response
Returns:
Properly formatted MCP tool response
"""
if isinstance(data, str):
text = data
elif isinstance(data, dict):
if data.get("success") is False:
is_error = True
text = data.get("message", "Unknown error")
else:
# Format the dict nicely
import json
text = json.dumps(data, indent=2, default=str)
else:
text = str(data)
return {
"content": [{"type": "text", "text": text}],
"is_error": is_error
}