This commit is contained in:
Taylor Wilsdon
2026-03-01 16:00:39 -05:00
parent 1f34a8b8cc
commit 49073995c9
3 changed files with 577 additions and 775 deletions

View File

@@ -492,7 +492,7 @@ async def manage_deployment(
"""
action = action.lower().strip()
if action == "create":
if not description:
if description is None or description.strip() == "":
raise ValueError("description is required for create action")
return await _create_deployment_impl(
service, user_google_email, script_id, description, version_description
@@ -500,7 +500,7 @@ async def manage_deployment(
elif action == "update":
if not deployment_id:
raise ValueError("deployment_id is required for update action")
if description is None or description == "":
if description is None or description.strip() == "":
raise ValueError("description is required for update action")
return await _update_deployment_impl(
service, user_google_email, script_id, deployment_id, description

View File

@@ -249,7 +249,6 @@ async def list_contacts(
"""
logger.info(f"[list_contacts] Invoked. Email: '{user_google_email}'")
try:
params: Dict[str, Any] = {
"resourceName": "people/me",
"personFields": DEFAULT_PERSON_FIELDS,
@@ -272,7 +271,9 @@ async def list_contacts(
if not connections:
return f"No contacts found for {user_google_email}."
response = f"Contacts for {user_google_email} ({len(connections)} of {total_people}):\n\n"
response = (
f"Contacts for {user_google_email} ({len(connections)} of {total_people}):\n\n"
)
for person in connections:
response += _format_contact(person) + "\n\n"
@@ -283,15 +284,6 @@ async def list_contacts(
logger.info(f"Found {len(connections)} contacts for {user_google_email}")
return response
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 Contacts'."
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("people", "contacts_read")
@@ -321,7 +313,6 @@ async def get_contact(
f"[get_contact] Invoked. Email: '{user_google_email}', Contact: {resource_name}"
)
try:
person = await asyncio.to_thread(
service.people()
.get(resourceName=resource_name, personFields=DETAILED_PERSON_FIELDS)
@@ -334,19 +325,6 @@ async def get_contact(
logger.info(f"Retrieved contact {resource_name} for {user_google_email}")
return response
except HttpError as error:
if error.resp.status == 404:
message = f"Contact not found: {contact_id}"
logger.warning(message)
raise Exception(message)
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 Contacts'."
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("people", "contacts_read")
@@ -372,7 +350,6 @@ async def search_contacts(
f"[search_contacts] Invoked. Email: '{user_google_email}', Query: '{query}'"
)
try:
# Warm up the search cache if needed
await _warmup_search_cache(service, user_google_email)
@@ -402,15 +379,6 @@ async def search_contacts(
)
return response
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 Contacts'."
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("people", "contacts")
@@ -457,7 +425,6 @@ async def manage_contact(
f"[manage_contact] Invoked. Action: '{action}', Email: '{user_google_email}'"
)
try:
if action == "create":
body = _build_person_body(
given_name=given_name,
@@ -566,21 +533,6 @@ async def manage_contact(
logger.info(f"Deleted contact {resource_name} for {user_google_email}")
return response
except UserInputError:
raise
except HttpError as error:
if error.resp.status == 404:
message = f"Contact not found: {contact_id}"
logger.warning(message)
raise Exception(message)
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 Contacts'."
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
# =============================================================================
# Extended Tier Tools
@@ -609,7 +561,6 @@ async def list_contact_groups(
"""
logger.info(f"[list_contact_groups] Invoked. Email: '{user_google_email}'")
try:
params: Dict[str, Any] = {
"pageSize": min(page_size, 1000),
"groupFields": CONTACT_GROUP_FIELDS,
@@ -646,15 +597,6 @@ async def list_contact_groups(
logger.info(f"Found {len(groups)} contact groups for {user_google_email}")
return response
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 Contacts'."
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("people", "contacts_read")
@@ -686,7 +628,6 @@ async def get_contact_group(
f"[get_contact_group] Invoked. Email: '{user_google_email}', Group: {resource_name}"
)
try:
result = await asyncio.to_thread(
service.contactGroups()
.get(
@@ -717,19 +658,6 @@ async def get_contact_group(
logger.info(f"Retrieved contact group {resource_name} for {user_google_email}")
return response
except HttpError as error:
if error.resp.status == 404:
message = f"Contact group not found: {group_id}"
logger.warning(message)
raise Exception(message)
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 Contacts'."
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
# =============================================================================
# Complete Tier Tools
@@ -774,12 +702,9 @@ async def manage_contacts_batch(
f"[manage_contacts_batch] Invoked. Action: '{action}', Email: '{user_google_email}'"
)
try:
if action == "create":
if not contacts:
raise UserInputError(
"contacts parameter is required for 'create' action."
)
raise UserInputError("contacts parameter is required for 'create' action.")
if len(contacts) > 200:
raise UserInputError("Maximum 200 contacts can be created in a batch.")
@@ -825,9 +750,7 @@ async def manage_contacts_batch(
if action == "update":
if not updates:
raise UserInputError(
"updates parameter is required for 'update' action."
)
raise UserInputError("updates parameter is required for 'update' action.")
if len(updates) > 200:
raise UserInputError("Maximum 200 contacts can be updated in a batch.")
@@ -924,9 +847,7 @@ async def manage_contacts_batch(
# action == "delete"
if not contact_ids:
raise UserInputError(
"contact_ids parameter is required for 'delete' action."
)
raise UserInputError("contact_ids parameter is required for 'delete' action.")
if len(contact_ids) > 500:
raise UserInputError("Maximum 500 contacts can be deleted in a batch.")
@@ -945,22 +866,9 @@ async def manage_contacts_batch(
)
response = f"Batch deleted {len(contact_ids)} contacts for {user_google_email}."
logger.info(
f"Batch deleted {len(contact_ids)} contacts for {user_google_email}"
)
logger.info(f"Batch deleted {len(contact_ids)} contacts for {user_google_email}")
return response
except UserInputError:
raise
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 Contacts'."
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("people", "contacts")
@@ -1004,7 +912,6 @@ async def manage_contact_group(
f"[manage_contact_group] Invoked. Action: '{action}', Email: '{user_google_email}'"
)
try:
if action == "create":
if not name:
raise UserInputError("name is required for 'create' action.")
@@ -1055,9 +962,7 @@ async def manage_contact_group(
response += f"Name: {updated_name}\n"
response += f"ID: {group_id}\n"
logger.info(
f"Updated contact group {resource_name} for {user_google_email}"
)
logger.info(f"Updated contact group {resource_name} for {user_google_email}")
return response
if action == "delete":
@@ -1067,17 +972,13 @@ async def manage_contact_group(
.execute
)
response = (
f"Contact group {group_id} has been deleted for {user_google_email}."
)
response = f"Contact group {group_id} has been deleted for {user_google_email}."
if delete_contacts:
response += " Contacts in the group were also deleted."
else:
response += " Contacts in the group were preserved."
logger.info(
f"Deleted contact group {resource_name} for {user_google_email}"
)
logger.info(f"Deleted contact group {resource_name} for {user_google_email}")
return response
# action == "modify_members"
@@ -1133,18 +1034,3 @@ async def manage_contact_group(
f"Modified contact group members for {resource_name} for {user_google_email}"
)
return response
except UserInputError:
raise
except HttpError as error:
if error.resp.status == 404:
message = f"Contact group not found: {group_id}"
logger.warning(message)
raise Exception(message)
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 Contacts'."
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)

View File

@@ -204,7 +204,6 @@ async def _create_task_list_impl(
f"[create_task_list] Invoked. Email: '{user_google_email}', Title: '{title}'"
)
try:
body = {"title": title}
result = await asyncio.to_thread(service.tasklists().insert(body=body).execute)
@@ -220,15 +219,6 @@ async def _create_task_list_impl(
)
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
async def _update_task_list_impl(
service: Resource, user_google_email: str, task_list_id: str, title: str
@@ -238,7 +228,6 @@ async def _update_task_list_impl(
f"[update_task_list] Invoked. Email: '{user_google_email}', Task List ID: {task_list_id}, New Title: '{title}'"
)
try:
body = {"id": task_list_id, "title": title}
result = await asyncio.to_thread(
@@ -255,15 +244,6 @@ async def _update_task_list_impl(
)
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
async def _delete_task_list_impl(
service: Resource, user_google_email: str, task_list_id: str
@@ -273,25 +253,13 @@ async def _delete_task_list_impl(
f"[delete_task_list] Invoked. Email: '{user_google_email}', Task List ID: {task_list_id}"
)
try:
await asyncio.to_thread(
service.tasklists().delete(tasklist=task_list_id).execute
)
await asyncio.to_thread(service.tasklists().delete(tasklist=task_list_id).execute)
response = f"Task list {task_list_id} has been deleted for {user_google_email}. All tasks in this list have also been deleted."
logger.info(f"Deleted task list {task_list_id} for {user_google_email}")
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
async def _clear_completed_tasks_impl(
service: Resource, user_google_email: str, task_list_id: str
@@ -301,7 +269,6 @@ async def _clear_completed_tasks_impl(
f"[clear_completed_tasks] Invoked. Email: '{user_google_email}', Task List ID: {task_list_id}"
)
try:
await asyncio.to_thread(service.tasks().clear(tasklist=task_list_id).execute)
response = f"All completed tasks have been cleared from task list {task_list_id} for {user_google_email}. The tasks are now hidden and won't appear in default task list views."
@@ -311,15 +278,6 @@ async def _clear_completed_tasks_impl(
)
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
# --- Consolidated manage_task_list tool ---
@@ -710,7 +668,6 @@ async def _create_task_impl(
f"[create_task] Invoked. Email: '{user_google_email}', Task List ID: {task_list_id}, Title: '{title}'"
)
try:
body = {"title": title}
if notes:
body["notes"] = notes
@@ -743,15 +700,6 @@ async def _create_task_impl(
)
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
async def _update_task_impl(
service: Resource,
@@ -768,7 +716,6 @@ async def _update_task_impl(
f"[update_task] Invoked. Email: '{user_google_email}', Task List ID: {task_list_id}, Task ID: {task_id}"
)
try:
# First get the current task to build the update body
current_task = await asyncio.to_thread(
service.tasks().get(tasklist=task_list_id, task=task_id).execute
@@ -793,9 +740,7 @@ async def _update_task_impl(
body["due"] = current_task["due"]
result = await asyncio.to_thread(
service.tasks()
.update(tasklist=task_list_id, task=task_id, body=body)
.execute
service.tasks().update(tasklist=task_list_id, task=task_id, body=body).execute
)
response = f"""Task Updated for {user_google_email}:
@@ -814,15 +759,6 @@ async def _update_task_impl(
logger.info(f"Updated task {task_id} for {user_google_email}")
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
async def _delete_task_impl(
service: Resource, user_google_email: str, task_list_id: str, task_id: str
@@ -832,7 +768,6 @@ async def _delete_task_impl(
f"[delete_task] Invoked. Email: '{user_google_email}', Task List ID: {task_list_id}, Task ID: {task_id}"
)
try:
await asyncio.to_thread(
service.tasks().delete(tasklist=task_list_id, task=task_id).execute
)
@@ -842,15 +777,6 @@ async def _delete_task_impl(
logger.info(f"Deleted task {task_id} for {user_google_email}")
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
async def _move_task_impl(
service: Resource,
@@ -866,7 +792,6 @@ async def _move_task_impl(
f"[move_task] Invoked. Email: '{user_google_email}', Task List ID: {task_list_id}, Task ID: {task_id}"
)
try:
params = {"tasklist": task_list_id, "task": task_id}
if parent:
params["parent"] = parent
@@ -902,15 +827,6 @@ async def _move_task_impl(
logger.info(f"Moved task {task_id} for {user_google_email}")
return response
except HttpError as error:
message = _format_reauth_message(error, user_google_email)
logger.error(message, exc_info=True)
raise Exception(message)
except Exception as e:
message = f"Unexpected error: {e}."
logger.exception(message)
raise Exception(message)
# --- Consolidated manage_task tool ---