diff --git a/gcontacts/contacts_tools.py b/gcontacts/contacts_tools.py index dd7143f..ab04053 100644 --- a/gcontacts/contacts_tools.py +++ b/gcontacts/contacts_tools.py @@ -249,10 +249,14 @@ async def list_contacts( """ logger.info(f"[list_contacts] Invoked. Email: '{user_google_email}'") + if page_size < 1: + raise UserInputError("page_size must be >= 1") + page_size = min(page_size, 1000) + params: Dict[str, Any] = { "resourceName": "people/me", "personFields": DEFAULT_PERSON_FIELDS, - "pageSize": min(page_size, 1000), + "pageSize": page_size, } if page_token: @@ -350,6 +354,10 @@ async def search_contacts( f"[search_contacts] Invoked. Email: '{user_google_email}', Query: '{query}'" ) + if page_size < 1: + raise UserInputError("page_size must be >= 1") + page_size = min(page_size, 30) + # Warm up the search cache if needed await _warmup_search_cache(service, user_google_email) @@ -358,7 +366,7 @@ async def search_contacts( .searchContacts( query=query, readMask=DEFAULT_PERSON_FIELDS, - pageSize=min(page_size, 30), + pageSize=page_size, ) .execute ) @@ -561,8 +569,12 @@ async def list_contact_groups( """ logger.info(f"[list_contact_groups] Invoked. Email: '{user_google_email}'") + if page_size < 1: + raise UserInputError("page_size must be >= 1") + page_size = min(page_size, 1000) + params: Dict[str, Any] = { - "pageSize": min(page_size, 1000), + "pageSize": page_size, "groupFields": CONTACT_GROUP_FIELDS, } @@ -628,11 +640,15 @@ async def get_contact_group( f"[get_contact_group] Invoked. Email: '{user_google_email}', Group: {resource_name}" ) + if max_members < 1: + raise UserInputError("max_members must be >= 1") + max_members = min(max_members, 1000) + result = await asyncio.to_thread( service.contactGroups() .get( resourceName=resource_name, - maxMembers=min(max_members, 1000), + maxMembers=max_members, groupFields=CONTACT_GROUP_FIELDS, ) .execute diff --git a/gtasks/tasks_tools.py b/gtasks/tasks_tools.py index 7607183..28cbaab 100644 --- a/gtasks/tasks_tools.py +++ b/gtasks/tasks_tools.py @@ -341,7 +341,7 @@ async def manage_task_list( return await _clear_completed_tasks_impl(service, user_google_email, task_list_id) -# --- Legacy task list tools (wrappers around _impl functions) --- +# --- Task tools --- @server.tool() # type: ignore @@ -871,6 +871,12 @@ async def manage_task( f"[manage_task] Invoked. Email: '{user_google_email}', Action: '{action}', Task List ID: {task_list_id}" ) + allowed_statuses = {"needsAction", "completed"} + if status is not None and status not in allowed_statuses: + raise UserInputError( + "invalid status: must be 'needsAction' or 'completed'" + ) + valid_actions = ("create", "update", "delete", "move") if action not in valid_actions: raise UserInputError( @@ -878,6 +884,8 @@ async def manage_task( ) if action == "create": + if status is not None: + raise UserInputError("'status' is only supported for the 'update' action.") if not title: raise UserInputError("'title' is required for the 'create' action.") return await _create_task_impl( @@ -892,6 +900,10 @@ async def manage_task( ) if action == "update": + if status is not None and status not in allowed_statuses: + raise UserInputError( + "invalid status: must be 'needsAction' or 'completed'" + ) if not task_id: raise UserInputError("'task_id' is required for the 'update' action.") return await _update_task_impl( @@ -924,6 +936,3 @@ async def manage_task( previous=previous, destination_task_list=destination_task_list, ) - - -# --- Legacy task tools (wrappers around _impl functions) ---