handle_http_errors decorator to simplify tool error handling
This commit is contained in:
@@ -160,3 +160,39 @@ def extract_office_xml_text(file_bytes: bytes, mime_type: str) -> Optional[str]:
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to extract office XML text for {mime_type}: {e}", exc_info=True)
|
||||
return None
|
||||
|
||||
import functools
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
def handle_http_errors(tool_name: str):
|
||||
"""
|
||||
A decorator to handle Google API HttpErrors in a standardized way.
|
||||
|
||||
It wraps a tool function, catches HttpError, logs a detailed error message,
|
||||
and raises a generic Exception with a user-friendly message.
|
||||
|
||||
Args:
|
||||
tool_name (str): The name of the tool being decorated (e.g., 'list_calendars').
|
||||
This is used for logging purposes.
|
||||
"""
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
async def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except HttpError as error:
|
||||
user_google_email = kwargs.get('user_google_email', 'N/A')
|
||||
message = (
|
||||
f"API error in {tool_name}: {error}. "
|
||||
f"You might need to re-authenticate for user '{user_google_email}'. "
|
||||
f"LLM: Try 'start_google_auth' with the user's email and the appropriate service_name."
|
||||
)
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
# Catch any other unexpected errors
|
||||
message = f"An unexpected error occurred in {tool_name}: {e}"
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@@ -15,6 +15,7 @@ from mcp import types
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
from core.server import server
|
||||
|
||||
@@ -81,6 +82,7 @@ def _correct_time_format_for_api(
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_read")
|
||||
@handle_http_errors("list_calendars")
|
||||
async def list_calendars(service, user_google_email: str) -> str:
|
||||
"""
|
||||
Retrieves a list of calendars accessible to the authenticated user.
|
||||
@@ -93,7 +95,6 @@ async def list_calendars(service, user_google_email: str) -> str:
|
||||
"""
|
||||
logger.info(f"[list_calendars] Invoked. Email: '{user_google_email}'")
|
||||
|
||||
try:
|
||||
calendar_list_response = await asyncio.to_thread(
|
||||
service.calendarList().list().execute
|
||||
)
|
||||
@@ -111,18 +112,11 @@ async def list_calendars(service, user_google_email: str) -> str:
|
||||
)
|
||||
logger.info(f"Successfully listed {len(items)} calendars for {user_google_email}.")
|
||||
return text_output
|
||||
except HttpError as error:
|
||||
message = f"API error listing calendars: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Calendar'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error listing calendars: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_read")
|
||||
@handle_http_errors("get_events")
|
||||
async def get_events(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -144,7 +138,6 @@ async def get_events(
|
||||
Returns:
|
||||
str: A formatted list of events (summary, start and end times, link) within the specified range.
|
||||
"""
|
||||
try:
|
||||
logger.info(
|
||||
f"[get_events] Raw time parameters - time_min: '{time_min}', time_max: '{time_max}'"
|
||||
)
|
||||
@@ -208,18 +201,11 @@ async def get_events(
|
||||
)
|
||||
logger.info(f"Successfully retrieved {len(items)} events for {user_google_email}.")
|
||||
return text_output
|
||||
except HttpError as error:
|
||||
message = f"API error getting events: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Calendar'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error getting events: {e}"
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
@handle_http_errors("create_event")
|
||||
async def create_event(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -253,7 +239,6 @@ async def create_event(
|
||||
f"[create_event] Invoked. Email: '{user_google_email}', Summary: {summary}"
|
||||
)
|
||||
|
||||
try:
|
||||
event_body: Dict[str, Any] = {
|
||||
"summary": summary,
|
||||
"start": (
|
||||
@@ -287,18 +272,11 @@ async def create_event(
|
||||
f"Event created successfully for {user_google_email}. ID: {created_event.get('id')}, Link: {link}"
|
||||
)
|
||||
return confirmation_message
|
||||
except HttpError as error:
|
||||
message = f"API error creating event: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Calendar'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error creating event: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
@handle_http_errors("modify_event")
|
||||
async def modify_event(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -334,7 +312,6 @@ async def modify_event(
|
||||
f"[modify_event] Invoked. Email: '{user_google_email}', Event ID: {event_id}"
|
||||
)
|
||||
|
||||
try:
|
||||
# Build the event body with only the fields that are provided
|
||||
event_body: Dict[str, Any] = {}
|
||||
if summary is not None:
|
||||
@@ -415,23 +392,11 @@ async def modify_event(
|
||||
f"Event modified successfully for {user_google_email}. ID: {updated_event.get('id')}, Link: {link}"
|
||||
)
|
||||
return confirmation_message
|
||||
except HttpError as error:
|
||||
# Check for 404 Not Found error specifically
|
||||
if error.resp.status == 404:
|
||||
message = f"Event not found. The event with ID '{event_id}' could not be found in calendar '{calendar_id}'. LLM: The event may have been deleted, or the event ID might be incorrect. Verify the event exists using 'get_events' before attempting to modify it."
|
||||
logger.error(f"[modify_event] {message}")
|
||||
else:
|
||||
message = f"API error modifying event (ID: {event_id}): {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Calendar'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error modifying event (ID: {event_id}): {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
@handle_http_errors("delete_event")
|
||||
async def delete_event(service, user_google_email: str, event_id: str, calendar_id: str = "primary") -> str:
|
||||
"""
|
||||
Deletes an existing event.
|
||||
@@ -448,7 +413,6 @@ async def delete_event(service, user_google_email: str, event_id: str, calendar_
|
||||
f"[delete_event] Invoked. Email: '{user_google_email}', Event ID: {event_id}"
|
||||
)
|
||||
|
||||
try:
|
||||
# Log the event ID for debugging
|
||||
logger.info(
|
||||
f"[delete_event] Attempting to delete event with ID: '{event_id}' in calendar '{calendar_id}'"
|
||||
@@ -482,16 +446,3 @@ async def delete_event(service, user_google_email: str, event_id: str, calendar_
|
||||
confirmation_message = f"Successfully deleted event (ID: {event_id}) from calendar '{calendar_id}' for {user_google_email}."
|
||||
logger.info(f"Event deleted successfully for {user_google_email}. ID: {event_id}")
|
||||
return confirmation_message
|
||||
except HttpError as error:
|
||||
# Check for 404 Not Found error specifically
|
||||
if error.resp.status == 404:
|
||||
message = f"Event not found. The event with ID '{event_id}' could not be found in calendar '{calendar_id}'. LLM: The event may have been deleted already, or the event ID might be incorrect."
|
||||
logger.error(f"[delete_event] {message}")
|
||||
else:
|
||||
message = f"API error deleting event (ID: {event_id}): {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Calendar'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error deleting event (ID: {event_id}): {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
@@ -13,11 +13,13 @@ from googleapiclient.errors import HttpError
|
||||
# Auth & server utilities
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("chat", "chat_read")
|
||||
@handle_http_errors("list_spaces")
|
||||
async def list_spaces(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -32,7 +34,6 @@ async def list_spaces(
|
||||
"""
|
||||
logger.info(f"[list_spaces] Email={user_google_email}, Type={space_type}")
|
||||
|
||||
try:
|
||||
# Build filter based on space_type
|
||||
filter_param = None
|
||||
if space_type == "room":
|
||||
@@ -61,15 +62,9 @@ async def list_spaces(
|
||||
|
||||
return "\n".join(output)
|
||||
|
||||
except HttpError as e:
|
||||
logger.error(f"API error in list_spaces: {e}", exc_info=True)
|
||||
raise Exception(f"API error: {e}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error in list_spaces: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("chat", "chat_read")
|
||||
@handle_http_errors("get_messages")
|
||||
async def get_messages(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -85,7 +80,6 @@ async def get_messages(
|
||||
"""
|
||||
logger.info(f"[get_messages] Space ID: '{space_id}' for user '{user_google_email}'")
|
||||
|
||||
try:
|
||||
# Get space info first
|
||||
space_info = await asyncio.to_thread(
|
||||
service.spaces().get(name=space_id).execute
|
||||
@@ -118,15 +112,9 @@ async def get_messages(
|
||||
|
||||
return "\n".join(output)
|
||||
|
||||
except HttpError as error:
|
||||
logger.error(f"[get_messages] API error for space {space_id}: {error}", exc_info=True)
|
||||
raise Exception(f"API error accessing space {space_id}: {error}")
|
||||
except Exception as e:
|
||||
logger.exception(f"[get_messages] Unexpected error for space {space_id}: {e}")
|
||||
raise Exception(f"Unexpected error accessing space {space_id}: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("chat", "chat_write")
|
||||
@handle_http_errors("send_message")
|
||||
async def send_message(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -142,7 +130,6 @@ async def send_message(
|
||||
"""
|
||||
logger.info(f"[send_message] Email: '{user_google_email}', Space: '{space_id}'")
|
||||
|
||||
try:
|
||||
message_body = {
|
||||
'text': message_text
|
||||
}
|
||||
@@ -166,15 +153,9 @@ async def send_message(
|
||||
logger.info(f"Successfully sent message to space '{space_id}' by {user_google_email}")
|
||||
return msg
|
||||
|
||||
except HttpError as e:
|
||||
logger.error(f"API error in send_message: {e}", exc_info=True)
|
||||
raise Exception(f"API error: {e}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error in send_message: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("chat", "chat_read")
|
||||
@handle_http_errors("search_messages")
|
||||
async def search_messages(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -190,7 +171,6 @@ async def search_messages(
|
||||
"""
|
||||
logger.info(f"[search_messages] Email={user_google_email}, Query='{query}'")
|
||||
|
||||
try:
|
||||
# If specific space provided, search within that space
|
||||
if space_id:
|
||||
response = await asyncio.to_thread(
|
||||
@@ -245,10 +225,3 @@ async def search_messages(
|
||||
output.append(f"- [{create_time}] {sender} in '{space_name}': {text_content}")
|
||||
|
||||
return "\n".join(output)
|
||||
|
||||
except HttpError as e:
|
||||
logger.error(f"API error in search_messages: {e}", exc_info=True)
|
||||
raise Exception(f"API error: {e}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error in search_messages: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
@@ -14,13 +14,14 @@ from googleapiclient.http import MediaIoBaseDownload
|
||||
|
||||
# Auth & server utilities
|
||||
from auth.service_decorator import require_google_service, require_multiple_services
|
||||
from core.utils import extract_office_xml_text
|
||||
from core.utils import extract_office_xml_text, handle_http_errors
|
||||
from core.server import server
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("search_docs")
|
||||
async def search_docs(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -35,7 +36,6 @@ async def search_docs(
|
||||
"""
|
||||
logger.info(f"[search_docs] Email={user_google_email}, Query='{query}'")
|
||||
|
||||
try:
|
||||
escaped_query = query.replace("'", "\\'")
|
||||
|
||||
response = await asyncio.to_thread(
|
||||
@@ -56,15 +56,12 @@ async def search_docs(
|
||||
)
|
||||
return "\n".join(output)
|
||||
|
||||
except HttpError as e:
|
||||
logger.error(f"API error in search_docs: {e}", exc_info=True)
|
||||
raise Exception(f"API error: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_multiple_services([
|
||||
{"service_type": "drive", "scopes": "drive_read", "param_name": "drive_service"},
|
||||
{"service_type": "docs", "scopes": "docs_read", "param_name": "docs_service"}
|
||||
])
|
||||
@handle_http_errors("get_doc_content")
|
||||
async def get_doc_content(
|
||||
drive_service,
|
||||
docs_service,
|
||||
@@ -81,7 +78,6 @@ async def get_doc_content(
|
||||
"""
|
||||
logger.info(f"[get_doc_content] Invoked. Document/File ID: '{document_id}' for user '{user_google_email}'")
|
||||
|
||||
try:
|
||||
# Step 2: Get file metadata from Drive
|
||||
file_metadata = await asyncio.to_thread(
|
||||
drive_service.files().get(
|
||||
@@ -160,18 +156,9 @@ async def get_doc_content(
|
||||
)
|
||||
return header + body_text
|
||||
|
||||
except HttpError as error:
|
||||
logger.error(
|
||||
f"[get_doc_content] API error for ID {document_id}: {error}",
|
||||
exc_info=True,
|
||||
)
|
||||
raise Exception(f"API error processing document/file ID {document_id}: {error}")
|
||||
except Exception as e:
|
||||
logger.exception(f"[get_doc_content] Unexpected error for ID {document_id}: {e}")
|
||||
raise Exception(f"Unexpected error processing document/file ID {document_id}: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("list_docs_in_folder")
|
||||
async def list_docs_in_folder(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -186,7 +173,6 @@ async def list_docs_in_folder(
|
||||
"""
|
||||
logger.info(f"[list_docs_in_folder] Invoked. Email: '{user_google_email}', Folder ID: '{folder_id}'")
|
||||
|
||||
try:
|
||||
rsp = await asyncio.to_thread(
|
||||
service.files().list(
|
||||
q=f"'{folder_id}' in parents and mimeType='application/vnd.google-apps.document' and trashed=false",
|
||||
@@ -202,18 +188,12 @@ async def list_docs_in_folder(
|
||||
out.append(f"- {f['name']} (ID: {f['id']}) Modified: {f.get('modifiedTime')} Link: {f.get('webViewLink')}")
|
||||
return "\n".join(out)
|
||||
|
||||
except HttpError as e:
|
||||
logger.error(f"API error in list_docs_in_folder: {e}", exc_info=True)
|
||||
raise Exception(f"API error: {e}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error in list_docs_in_folder: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("docs", "docs_write")
|
||||
@handle_http_errors("create_doc")
|
||||
async def create_doc(
|
||||
service,
|
||||
user_google_email: str, # Made user_google_email required
|
||||
user_google_email: str,
|
||||
title: str,
|
||||
content: str = '',
|
||||
) -> str:
|
||||
@@ -225,7 +205,6 @@ async def create_doc(
|
||||
"""
|
||||
logger.info(f"[create_doc] Invoked. Email: '{user_google_email}', Title='{title}'")
|
||||
|
||||
try:
|
||||
doc = await asyncio.to_thread(service.documents().create(body={'title': title}).execute)
|
||||
doc_id = doc.get('documentId')
|
||||
if content:
|
||||
@@ -235,10 +214,3 @@ async def create_doc(
|
||||
msg = f"Created Google Doc '{title}' (ID: {doc_id}) for {user_google_email}. Link: {link}"
|
||||
logger.info(f"Successfully created Google Doc '{title}' (ID: {doc_id}) for {user_google_email}. Link: {link}")
|
||||
return msg
|
||||
|
||||
except HttpError as e:
|
||||
logger.error(f"API error in create_doc: {e}", exc_info=True)
|
||||
raise Exception(f"API error: {e}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error in create_doc: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
|
||||
@@ -14,7 +14,7 @@ from googleapiclient.http import MediaIoBaseDownload, MediaIoBaseUpload
|
||||
import io
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.utils import extract_office_xml_text
|
||||
from core.utils import extract_office_xml_text, handle_http_errors
|
||||
from core.server import server
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -76,6 +76,7 @@ def _build_drive_list_params(
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("search_drive_files")
|
||||
async def search_drive_files(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -103,7 +104,6 @@ async def search_drive_files(
|
||||
"""
|
||||
logger.info(f"[search_drive_files] Invoked. Email: '{user_google_email}', Query: '{query}'")
|
||||
|
||||
try:
|
||||
# Check if the query looks like a structured Drive query or free text
|
||||
# Look for Drive API operators and structured query patterns
|
||||
is_structured_query = any(pattern.search(query) for pattern in DRIVE_QUERY_PATTERNS)
|
||||
@@ -140,15 +140,10 @@ async def search_drive_files(
|
||||
)
|
||||
text_output = "\n".join(formatted_files_text_parts)
|
||||
return text_output
|
||||
except HttpError as error:
|
||||
logger.error(f"API error searching Drive files: {error}", exc_info=True)
|
||||
raise Exception(f"API error: {error}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error searching Drive files: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("get_drive_file_content")
|
||||
async def get_drive_file_content(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -171,7 +166,6 @@ async def get_drive_file_content(
|
||||
"""
|
||||
logger.info(f"[get_drive_file_content] Invoked. File ID: '{file_id}'")
|
||||
|
||||
try:
|
||||
file_metadata = await asyncio.to_thread(
|
||||
service.files().get(
|
||||
fileId=file_id, fields="id, name, mimeType, webViewLink", supportsAllDrives=True
|
||||
@@ -236,18 +230,10 @@ async def get_drive_file_content(
|
||||
)
|
||||
return header + body_text
|
||||
|
||||
except HttpError as error:
|
||||
logger.error(
|
||||
f"API error getting Drive file content for {file_id}: {error}",
|
||||
exc_info=True,
|
||||
)
|
||||
raise Exception(f"API error: {error}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error getting Drive file content for {file_id}: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("list_drive_items")
|
||||
async def list_drive_items(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -275,7 +261,6 @@ async def list_drive_items(
|
||||
"""
|
||||
logger.info(f"[list_drive_items] Invoked. Email: '{user_google_email}', Folder ID: '{folder_id}'")
|
||||
|
||||
try:
|
||||
final_query = f"'{folder_id}' in parents and trashed=false"
|
||||
|
||||
list_params = _build_drive_list_params(
|
||||
@@ -301,14 +286,10 @@ async def list_drive_items(
|
||||
)
|
||||
text_output = "\n".join(formatted_items_text_parts)
|
||||
return text_output
|
||||
except HttpError as error:
|
||||
logger.error(f"API error listing Drive items in folder {folder_id}: {error}", exc_info=True)
|
||||
raise Exception(f"API error: {error}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error listing Drive items in folder {folder_id}: {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_file")
|
||||
@handle_http_errors("create_drive_file")
|
||||
async def create_drive_file(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -332,7 +313,6 @@ async def create_drive_file(
|
||||
"""
|
||||
logger.info(f"[create_drive_file] Invoked. Email: '{user_google_email}', File Name: {file_name}, Folder ID: {folder_id}")
|
||||
|
||||
try:
|
||||
file_metadata = {
|
||||
'name': file_name,
|
||||
'parents': [folder_id],
|
||||
@@ -353,10 +333,3 @@ async def create_drive_file(
|
||||
confirmation_message = f"Successfully created file '{created_file.get('name', file_name)}' (ID: {created_file.get('id', 'N/A')}) in folder '{folder_id}' for {user_google_email}. Link: {link}"
|
||||
logger.info(f"Successfully created file. Link: {link}")
|
||||
return confirmation_message
|
||||
|
||||
except HttpError as error:
|
||||
logger.error(f"API error creating Drive file '{file_name}': {error}", exc_info=True)
|
||||
raise Exception(f"API error: {error}")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error creating Drive file '{file_name}': {e}")
|
||||
raise Exception(f"Unexpected error: {e}")
|
||||
@@ -13,12 +13,14 @@ from googleapiclient.errors import HttpError
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("create_form")
|
||||
async def create_form(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -40,7 +42,6 @@ async def create_form(
|
||||
"""
|
||||
logger.info(f"[create_form] Invoked. Email: '{user_google_email}', Title: {title}")
|
||||
|
||||
try:
|
||||
form_body: Dict[str, Any] = {
|
||||
"info": {
|
||||
"title": title
|
||||
@@ -64,18 +65,11 @@ async def create_form(
|
||||
confirmation_message = f"Successfully created form '{created_form.get('info', {}).get('title', title)}' for {user_google_email}. Form ID: {form_id}. Edit URL: {edit_url}. Responder URL: {responder_url}"
|
||||
logger.info(f"Form created successfully for {user_google_email}. ID: {form_id}")
|
||||
return confirmation_message
|
||||
except HttpError as error:
|
||||
message = f"API error creating form: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error creating form: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("get_form")
|
||||
async def get_form(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -93,7 +87,6 @@ async def get_form(
|
||||
"""
|
||||
logger.info(f"[get_form] Invoked. Email: '{user_google_email}', Form ID: {form_id}")
|
||||
|
||||
try:
|
||||
form = await asyncio.to_thread(
|
||||
service.forms().get(formId=form_id).execute
|
||||
)
|
||||
@@ -128,18 +121,11 @@ async def get_form(
|
||||
|
||||
logger.info(f"Successfully retrieved form for {user_google_email}. ID: {form_id}")
|
||||
return result
|
||||
except HttpError as error:
|
||||
message = f"API error getting form: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error getting form: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("set_publish_settings")
|
||||
async def set_publish_settings(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -161,7 +147,6 @@ async def set_publish_settings(
|
||||
"""
|
||||
logger.info(f"[set_publish_settings] Invoked. Email: '{user_google_email}', Form ID: {form_id}")
|
||||
|
||||
try:
|
||||
settings_body = {
|
||||
"publishAsTemplate": publish_as_template,
|
||||
"requireAuthentication": require_authentication
|
||||
@@ -174,18 +159,11 @@ async def set_publish_settings(
|
||||
confirmation_message = f"Successfully updated publish settings for form {form_id} for {user_google_email}. Publish as template: {publish_as_template}, Require authentication: {require_authentication}"
|
||||
logger.info(f"Publish settings updated successfully for {user_google_email}. Form ID: {form_id}")
|
||||
return confirmation_message
|
||||
except HttpError as error:
|
||||
message = f"API error updating publish settings: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error updating publish settings: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("get_form_response")
|
||||
async def get_form_response(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -205,7 +183,6 @@ async def get_form_response(
|
||||
"""
|
||||
logger.info(f"[get_form_response] Invoked. Email: '{user_google_email}', Form ID: {form_id}, Response ID: {response_id}")
|
||||
|
||||
try:
|
||||
response = await asyncio.to_thread(
|
||||
service.forms().responses().get(formId=form_id, responseId=response_id).execute
|
||||
)
|
||||
@@ -236,18 +213,11 @@ async def get_form_response(
|
||||
|
||||
logger.info(f"Successfully retrieved response for {user_google_email}. Response ID: {response_id}")
|
||||
return result
|
||||
except HttpError as error:
|
||||
message = f"API error getting form response: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error getting form response: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("list_form_responses")
|
||||
async def list_form_responses(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -269,7 +239,6 @@ async def list_form_responses(
|
||||
"""
|
||||
logger.info(f"[list_form_responses] Invoked. Email: '{user_google_email}', Form ID: {form_id}")
|
||||
|
||||
try:
|
||||
params = {
|
||||
"formId": form_id,
|
||||
"pageSize": page_size
|
||||
@@ -308,11 +277,3 @@ async def list_form_responses(
|
||||
|
||||
logger.info(f"Successfully retrieved {len(responses)} responses for {user_google_email}. Form ID: {form_id}")
|
||||
return result
|
||||
except HttpError as error:
|
||||
message = f"API error listing form responses: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error listing form responses: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
@@ -13,6 +13,7 @@ from googleapiclient.errors import HttpError
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
# Configure module logger
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -20,6 +21,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("list_spreadsheets")
|
||||
async def list_spreadsheets(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -37,7 +39,6 @@ async def list_spreadsheets(
|
||||
"""
|
||||
logger.info(f"[list_spreadsheets] Invoked. Email: '{user_google_email}'")
|
||||
|
||||
try:
|
||||
files_response = await asyncio.to_thread(
|
||||
service.files()
|
||||
.list(
|
||||
@@ -66,18 +67,10 @@ async def list_spreadsheets(
|
||||
logger.info(f"Successfully listed {len(files)} spreadsheets for {user_google_email}.")
|
||||
return text_output
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error listing spreadsheets: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Sheets'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error listing spreadsheets: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_read")
|
||||
@handle_http_errors("get_spreadsheet_info")
|
||||
async def get_spreadsheet_info(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -95,7 +88,6 @@ async def get_spreadsheet_info(
|
||||
"""
|
||||
logger.info(f"[get_spreadsheet_info] Invoked. Email: '{user_google_email}', Spreadsheet ID: {spreadsheet_id}")
|
||||
|
||||
try:
|
||||
spreadsheet = await asyncio.to_thread(
|
||||
service.spreadsheets().get(spreadsheetId=spreadsheet_id).execute
|
||||
)
|
||||
@@ -125,18 +117,10 @@ async def get_spreadsheet_info(
|
||||
logger.info(f"Successfully retrieved info for spreadsheet {spreadsheet_id} for {user_google_email}.")
|
||||
return text_output
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error getting spreadsheet info: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Sheets'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error getting spreadsheet info: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_read")
|
||||
@handle_http_errors("read_sheet_values")
|
||||
async def read_sheet_values(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -156,7 +140,6 @@ async def read_sheet_values(
|
||||
"""
|
||||
logger.info(f"[read_sheet_values] Invoked. Email: '{user_google_email}', Spreadsheet: {spreadsheet_id}, Range: {range_name}")
|
||||
|
||||
try:
|
||||
result = await asyncio.to_thread(
|
||||
service.spreadsheets()
|
||||
.values()
|
||||
@@ -184,18 +167,10 @@ async def read_sheet_values(
|
||||
logger.info(f"Successfully read {len(values)} rows for {user_google_email}.")
|
||||
return text_output
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error reading sheet values: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Sheets'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error reading sheet values: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
@handle_http_errors("modify_sheet_values")
|
||||
async def modify_sheet_values(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -225,7 +200,6 @@ async def modify_sheet_values(
|
||||
if not clear_values and not values:
|
||||
raise Exception("Either 'values' must be provided or 'clear_values' must be True.")
|
||||
|
||||
try:
|
||||
if clear_values:
|
||||
result = await asyncio.to_thread(
|
||||
service.spreadsheets()
|
||||
@@ -264,18 +238,10 @@ async def modify_sheet_values(
|
||||
|
||||
return text_output
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error modifying sheet values: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Sheets'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error modifying sheet values: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
@handle_http_errors("create_spreadsheet")
|
||||
async def create_spreadsheet(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -295,7 +261,6 @@ async def create_spreadsheet(
|
||||
"""
|
||||
logger.info(f"[create_spreadsheet] Invoked. Email: '{user_google_email}', Title: {title}")
|
||||
|
||||
try:
|
||||
spreadsheet_body = {
|
||||
"properties": {
|
||||
"title": title
|
||||
@@ -322,18 +287,10 @@ async def create_spreadsheet(
|
||||
logger.info(f"Successfully created spreadsheet for {user_google_email}. ID: {spreadsheet_id}")
|
||||
return text_output
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error creating spreadsheet: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Sheets'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error creating spreadsheet: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
@handle_http_errors("create_sheet")
|
||||
async def create_sheet(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -353,7 +310,6 @@ async def create_sheet(
|
||||
"""
|
||||
logger.info(f"[create_sheet] Invoked. Email: '{user_google_email}', Spreadsheet: {spreadsheet_id}, Sheet: {sheet_name}")
|
||||
|
||||
try:
|
||||
request_body = {
|
||||
"requests": [
|
||||
{
|
||||
@@ -381,13 +337,4 @@ async def create_sheet(
|
||||
logger.info(f"Successfully created sheet for {user_google_email}. Sheet ID: {sheet_id}")
|
||||
return text_output
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error creating sheet: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with user's email and service_name='Google Sheets'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error creating sheet: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
|
||||
@@ -13,12 +13,14 @@ from googleapiclient.errors import HttpError
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("slides", "slides")
|
||||
@handle_http_errors("create_presentation")
|
||||
async def create_presentation(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -36,7 +38,6 @@ async def create_presentation(
|
||||
"""
|
||||
logger.info(f"[create_presentation] Invoked. Email: '{user_google_email}', Title: '{title}'")
|
||||
|
||||
try:
|
||||
body = {
|
||||
'title': title
|
||||
}
|
||||
@@ -57,18 +58,10 @@ async def create_presentation(
|
||||
logger.info(f"Presentation created successfully for {user_google_email}")
|
||||
return confirmation_message
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Slides'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("slides", "slides_read")
|
||||
@handle_http_errors("get_presentation")
|
||||
async def get_presentation(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -86,7 +79,6 @@ async def get_presentation(
|
||||
"""
|
||||
logger.info(f"[get_presentation] Invoked. Email: '{user_google_email}', ID: '{presentation_id}'")
|
||||
|
||||
try:
|
||||
result = await asyncio.to_thread(
|
||||
service.presentations().get(presentationId=presentation_id).execute
|
||||
)
|
||||
@@ -114,18 +106,10 @@ Slides Breakdown:
|
||||
logger.info(f"Presentation retrieved successfully for {user_google_email}")
|
||||
return confirmation_message
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Slides'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("slides", "slides")
|
||||
@handle_http_errors("batch_update_presentation")
|
||||
async def batch_update_presentation(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -145,7 +129,6 @@ async def batch_update_presentation(
|
||||
"""
|
||||
logger.info(f"[batch_update_presentation] Invoked. Email: '{user_google_email}', ID: '{presentation_id}', Requests: {len(requests)}")
|
||||
|
||||
try:
|
||||
body = {
|
||||
'requests': requests
|
||||
}
|
||||
@@ -180,18 +163,10 @@ async def batch_update_presentation(
|
||||
logger.info(f"Batch update completed successfully for {user_google_email}")
|
||||
return confirmation_message
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Slides'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("slides", "slides_read")
|
||||
@handle_http_errors("get_page")
|
||||
async def get_page(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -211,7 +186,6 @@ async def get_page(
|
||||
"""
|
||||
logger.info(f"[get_page] Invoked. Email: '{user_google_email}', Presentation: '{presentation_id}', Page: '{page_object_id}'")
|
||||
|
||||
try:
|
||||
result = await asyncio.to_thread(
|
||||
service.presentations().pages().get(
|
||||
presentationId=presentation_id,
|
||||
@@ -251,18 +225,10 @@ Page Elements:
|
||||
logger.info(f"Page retrieved successfully for {user_google_email}")
|
||||
return confirmation_message
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Slides'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("slides", "slides_read")
|
||||
@handle_http_errors("get_page_thumbnail")
|
||||
async def get_page_thumbnail(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -284,7 +250,6 @@ async def get_page_thumbnail(
|
||||
"""
|
||||
logger.info(f"[get_page_thumbnail] Invoked. Email: '{user_google_email}', Presentation: '{presentation_id}', Page: '{page_object_id}', Size: '{thumbnail_size}'")
|
||||
|
||||
try:
|
||||
result = await asyncio.to_thread(
|
||||
service.presentations().pages().getThumbnail(
|
||||
presentationId=presentation_id,
|
||||
@@ -305,12 +270,3 @@ You can view or download the thumbnail using the provided URL."""
|
||||
|
||||
logger.info(f"Thumbnail generated successfully for {user_google_email}")
|
||||
return confirmation_message
|
||||
|
||||
except HttpError as error:
|
||||
message = f"API error: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Slides'."
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
message = f"Unexpected error: {e}."
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
Reference in New Issue
Block a user