From 45de7d546c6258ffde72053ba773b5cab19060b6 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Fri, 13 Feb 2026 15:52:50 +0200 Subject: [PATCH] Refactor delete_notion_page: use page_title, add HITL, logging, not_found status --- .../new_chat/tools/notion/delete_page.py | 101 +++++++++++++----- .../new_chat/tools/notion/update_page.py | 4 +- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/surfsense_backend/app/agents/new_chat/tools/notion/delete_page.py b/surfsense_backend/app/agents/new_chat/tools/notion/delete_page.py index 2ae7dc564..c1656a1e8 100644 --- a/surfsense_backend/app/agents/new_chat/tools/notion/delete_page.py +++ b/surfsense_backend/app/agents/new_chat/tools/notion/delete_page.py @@ -1,14 +1,20 @@ +import logging from typing import Any from langchain_core.tools import tool +from langgraph.types import interrupt from sqlalchemy.ext.asyncio import AsyncSession from app.connectors.notion_history import NotionHistoryConnector +from app.services.notion.tool_metadata_service import NotionToolMetadataService + +logger = logging.getLogger(__name__) def create_delete_notion_page_tool( db_session: AsyncSession | None = None, search_space_id: int | None = None, + user_id: str | None = None, connector_id: int | None = None, ): """ @@ -17,6 +23,7 @@ def create_delete_notion_page_tool( Args: db_session: Database session for accessing Notion connector search_space_id: Search space ID to find the Notion connector + user_id: User ID for finding the correct Notion connector connector_id: Optional specific connector ID (if known) Returns: @@ -25,7 +32,7 @@ def create_delete_notion_page_tool( @tool async def delete_notion_page( - page_id: str, + page_title: str, ) -> dict[str, Any]: """Delete (archive) a Notion page. @@ -34,7 +41,7 @@ def create_delete_notion_page_tool( it archives them (they can be restored from trash). Args: - page_id: The ID of the Notion page to delete (required). + page_title: The title of the Notion page to delete. Returns: Dictionary with: @@ -43,57 +50,101 @@ def create_delete_notion_page_tool( - message: Success or error message Examples: - - "Delete the Notion page abc123" - - "Remove the page xyz789 from Notion" - - "Archive this Notion page: abc123" + - "Delete the 'Meeting Notes' Notion page" + - "Remove the 'Old Project Plan' Notion page" + - "Archive the 'Draft Ideas' Notion page" """ - if db_session is None or search_space_id is None: + logger.info(f"delete_notion_page called: page_title='{page_title}'") + + if db_session is None or search_space_id is None or user_id is None: + logger.error("Notion tool not properly configured - missing required parameters") return { "status": "error", "message": "Notion tool not properly configured. Please contact support.", } try: - # Get connector ID if not provided - actual_connector_id = connector_id - if actual_connector_id is None: - from sqlalchemy.future import select + # Get page context (page_id, account, title) from indexed data + metadata_service = NotionToolMetadataService(db_session) + context = await metadata_service.get_delete_context( + search_space_id, user_id, page_title + ) - from app.db import SearchSourceConnector, SearchSourceConnectorType - - result = await db_session.execute( - select(SearchSourceConnector).filter( - SearchSourceConnector.search_space_id == search_space_id, - SearchSourceConnector.connector_type - == SearchSourceConnectorType.NOTION_CONNECTOR, - ) - ) - connector = result.scalars().first() - - if not connector: + if "error" in context: + error_msg = context["error"] + # Check if it's a "not found" error (softer handling for LLM) + if "not found" in error_msg.lower(): + logger.warning(f"Page not found: {error_msg}") + return { + "status": "not_found", + "message": error_msg, + } + else: + logger.error(f"Failed to fetch delete context: {error_msg}") return { "status": "error", - "message": "No Notion connector found. Please connect Notion in your workspace settings.", + "message": error_msg, } - actual_connector_id = connector.id + page_id = context.get("page_id") + connector_id_from_context = context.get("account", {}).get("id") + + logger.info(f"Requesting approval for deleting Notion page: '{page_title}' (page_id={page_id})") + # Request approval before deleting + approval = interrupt( + { + "type": "notion_page_deletion", + "action": { + "tool": "delete_notion_page", + "params": { + "page_id": page_id, + "connector_id": connector_id_from_context, + }, + }, + "context": context, + } + ) + + decisions = approval.get("decisions", []) + if not decisions: + logger.warning("No approval decision received") + return { + "status": "error", + "message": "No approval decision received", + } + + decision = decisions[0] + decision_type = decision.get("type") or decision.get("decision_type") + logger.info(f"User decision: {decision_type}") + + if decision_type == "reject": + logger.info("Notion page deletion rejected by user") + return { + "status": "rejected", + "message": "User declined. The page was not deleted. Do not ask again or suggest alternatives.", + } + + logger.info(f"Deleting Notion page: page_id={page_id}") # Create connector instance notion_connector = NotionHistoryConnector( session=db_session, - connector_id=actual_connector_id, + connector_id=connector_id_from_context, ) # Delete the page result = await notion_connector.delete_page(page_id=page_id) + logger.info(f"delete_page result: {result.get('status')} - {result.get('message', '')}") return result except ValueError as e: + logger.error(f"ValueError in delete_notion_page: {e}") return { "status": "error", "message": str(e), } except Exception as e: + logger.error(f"Unexpected error in delete_notion_page: {e}") return { "status": "error", "message": f"Unexpected error deleting Notion page: {e!s}", diff --git a/surfsense_backend/app/agents/new_chat/tools/notion/update_page.py b/surfsense_backend/app/agents/new_chat/tools/notion/update_page.py index f705bc1d0..5e948e458 100644 --- a/surfsense_backend/app/agents/new_chat/tools/notion/update_page.py +++ b/surfsense_backend/app/agents/new_chat/tools/notion/update_page.py @@ -62,8 +62,8 @@ def create_update_notion_page_tool( ask the user to verify the page title or check if it's been indexed. Examples: - - "Add 'New meeting notes from today' to the 'Meeting Notes' page" - - "Append the following to 'Project Plan': '# Status Update\n\nCompleted phase 1'" + - "Add 'New meeting notes from today' to the 'Meeting Notes' Notion page" + - "Append the following to the 'Project Plan' Notion page: '# Status Update\n\nCompleted phase 1'" """ logger.info(f"update_notion_page called: page_title='{page_title}', content_length={len(content) if content else 0}")