mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-26 21:39:43 +02:00
use interrupt primitive with db context for notion page creation
This commit is contained in:
parent
c9b0e55ce9
commit
066fb6dbfb
4 changed files with 84 additions and 23 deletions
|
|
@ -274,7 +274,6 @@ async def create_surfsense_deep_agent(
|
||||||
context_schema=SurfSenseContextSchema,
|
context_schema=SurfSenseContextSchema,
|
||||||
checkpointer=checkpointer,
|
checkpointer=checkpointer,
|
||||||
interrupt_on={
|
interrupt_on={
|
||||||
"create_notion_page": True,
|
|
||||||
"delete_notion_page": {"allowed_decisions": ["approve", "reject"]},
|
"delete_notion_page": {"allowed_decisions": ["approve", "reject"]},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from langchain_core.tools import tool
|
from langchain_core.tools import tool
|
||||||
|
from langgraph.types import interrupt
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.connectors.notion_history import NotionHistoryConnector
|
from app.connectors.notion_history import NotionHistoryConnector
|
||||||
|
from app.services.notion import NotionToolMetadataService
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -12,6 +14,7 @@ logger = logging.getLogger(__name__)
|
||||||
def create_create_notion_page_tool(
|
def create_create_notion_page_tool(
|
||||||
db_session: AsyncSession | None = None,
|
db_session: AsyncSession | None = None,
|
||||||
search_space_id: int | None = None,
|
search_space_id: int | None = None,
|
||||||
|
user_id: str | None = None,
|
||||||
connector_id: int | None = None,
|
connector_id: int | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
|
@ -20,6 +23,7 @@ def create_create_notion_page_tool(
|
||||||
Args:
|
Args:
|
||||||
db_session: Database session for accessing Notion connector
|
db_session: Database session for accessing Notion connector
|
||||||
search_space_id: Search space ID to find the Notion connector
|
search_space_id: Search space ID to find the Notion connector
|
||||||
|
user_id: User ID for fetching user-specific context
|
||||||
connector_id: Optional specific connector ID (if known)
|
connector_id: Optional specific connector ID (if known)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -58,16 +62,74 @@ def create_create_notion_page_tool(
|
||||||
"""
|
"""
|
||||||
logger.info(f"create_notion_page called: title='{title}', parent_page_id={parent_page_id}")
|
logger.info(f"create_notion_page called: title='{title}', parent_page_id={parent_page_id}")
|
||||||
|
|
||||||
if db_session is None or search_space_id is None:
|
if db_session is None or search_space_id is None or user_id is None:
|
||||||
logger.error("Notion tool not properly configured - missing db_session or search_space_id")
|
logger.error("Notion tool not properly configured - missing required parameters")
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": "Notion tool not properly configured. Please contact support.",
|
"message": "Notion tool not properly configured. Please contact support.",
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get connector ID if not provided
|
metadata_service = NotionToolMetadataService(db_session)
|
||||||
actual_connector_id = connector_id
|
context = await metadata_service.get_creation_context(search_space_id, user_id)
|
||||||
|
|
||||||
|
if "error" in context:
|
||||||
|
logger.error(f"Failed to fetch creation context: {context['error']}")
|
||||||
|
return {
|
||||||
|
"status": "error",
|
||||||
|
"message": context["error"],
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Requesting approval for creating Notion page")
|
||||||
|
approval = interrupt({
|
||||||
|
"type": "notion_page_creation",
|
||||||
|
"message": f"Approve creating Notion page: '{title}'",
|
||||||
|
"action": {
|
||||||
|
"tool": "create_notion_page",
|
||||||
|
"params": {
|
||||||
|
"title": title,
|
||||||
|
"content": content,
|
||||||
|
"parent_page_id": parent_page_id,
|
||||||
|
"connector_id": connector_id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"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("decision_type")
|
||||||
|
|
||||||
|
if decision_type == "reject":
|
||||||
|
logger.info("Notion page creation rejected by user")
|
||||||
|
return {
|
||||||
|
"status": "rejected",
|
||||||
|
"message": "Page creation was rejected",
|
||||||
|
}
|
||||||
|
|
||||||
|
edited_action = decision.get("edited_action", {})
|
||||||
|
final_params = edited_action if edited_action else {
|
||||||
|
"title": title,
|
||||||
|
"content": content,
|
||||||
|
"parent_page_id": parent_page_id,
|
||||||
|
"connector_id": connector_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
final_title = final_params.get("title", title)
|
||||||
|
final_content = final_params.get("content", content)
|
||||||
|
final_parent_page_id = final_params.get("parent_page_id", parent_page_id)
|
||||||
|
final_connector_id = final_params.get("connector_id", connector_id)
|
||||||
|
|
||||||
|
logger.info(f"Creating Notion page with final params: title='{final_title}'")
|
||||||
|
|
||||||
|
actual_connector_id = final_connector_id
|
||||||
if actual_connector_id is None:
|
if actual_connector_id is None:
|
||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
||||||
|
|
@ -92,30 +154,29 @@ def create_create_notion_page_tool(
|
||||||
actual_connector_id = connector.id
|
actual_connector_id = connector.id
|
||||||
logger.info(f"Found Notion connector: id={actual_connector_id}")
|
logger.info(f"Found Notion connector: id={actual_connector_id}")
|
||||||
|
|
||||||
# Create connector instance
|
|
||||||
notion_connector = NotionHistoryConnector(
|
notion_connector = NotionHistoryConnector(
|
||||||
session=db_session,
|
session=db_session,
|
||||||
connector_id=actual_connector_id,
|
connector_id=actual_connector_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create the page
|
|
||||||
result = await notion_connector.create_page(
|
result = await notion_connector.create_page(
|
||||||
title=title, content=content, parent_page_id=parent_page_id
|
title=final_title,
|
||||||
|
content=final_content,
|
||||||
|
parent_page_id=final_parent_page_id,
|
||||||
)
|
)
|
||||||
logger.info(f"create_page result: {result.get('status')} - {result.get('message', '')}")
|
logger.info(f"create_page result: {result.get('status')} - {result.get('message', '')}")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
except ValueError as e:
|
|
||||||
logger.error(f"ValueError creating Notion page: {e}")
|
|
||||||
return {
|
|
||||||
"status": "error",
|
|
||||||
"message": str(e),
|
|
||||||
}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Unexpected error creating Notion page: {e}", exc_info=True)
|
from langgraph.errors import GraphInterrupt
|
||||||
|
|
||||||
|
if isinstance(e, GraphInterrupt):
|
||||||
|
raise
|
||||||
|
|
||||||
|
logger.error(f"Error creating Notion page: {e}", exc_info=True)
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"Unexpected error creating Notion page: {e!s}",
|
"message": str(e) if isinstance(e, ValueError) else f"Unexpected error: {e!s}",
|
||||||
}
|
}
|
||||||
|
|
||||||
return create_notion_page
|
return create_notion_page
|
||||||
|
|
|
||||||
|
|
@ -213,8 +213,9 @@ BUILTIN_TOOLS: list[ToolDefinition] = [
|
||||||
factory=lambda deps: create_create_notion_page_tool(
|
factory=lambda deps: create_create_notion_page_tool(
|
||||||
db_session=deps["db_session"],
|
db_session=deps["db_session"],
|
||||||
search_space_id=deps["search_space_id"],
|
search_space_id=deps["search_space_id"],
|
||||||
|
user_id=deps["user_id"],
|
||||||
),
|
),
|
||||||
requires=["db_session", "search_space_id"],
|
requires=["db_session", "search_space_id", "user_id"],
|
||||||
),
|
),
|
||||||
ToolDefinition(
|
ToolDefinition(
|
||||||
name="update_notion_page",
|
name="update_notion_page",
|
||||||
|
|
|
||||||
|
|
@ -983,7 +983,7 @@ class NotionHistoryConnector:
|
||||||
logger.error(f"Unexpected error creating Notion page: {e}")
|
logger.error(f"Unexpected error creating Notion page: {e}")
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"Failed to create Notion page: {str(e)}",
|
"message": f"Failed to create Notion page: {e!s}",
|
||||||
}
|
}
|
||||||
|
|
||||||
async def update_page(
|
async def update_page(
|
||||||
|
|
@ -1039,7 +1039,7 @@ class NotionHistoryConnector:
|
||||||
logger.error(f"Failed to convert markdown to blocks: {e}")
|
logger.error(f"Failed to convert markdown to blocks: {e}")
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"Failed to parse content: {str(e)}",
|
"message": f"Failed to parse content: {e!s}",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Store block count for logging
|
# Store block count for logging
|
||||||
|
|
@ -1057,7 +1057,7 @@ class NotionHistoryConnector:
|
||||||
logger.error(f"Failed to delete existing blocks: {e}")
|
logger.error(f"Failed to delete existing blocks: {e}")
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"Failed to clear existing content: {str(e)}",
|
"message": f"Failed to clear existing content: {e!s}",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add new content (CRITICAL: if this fails, content is lost) Need improvement to handle this better.
|
# Add new content (CRITICAL: if this fails, content is lost) Need improvement to handle this better.
|
||||||
|
|
@ -1103,7 +1103,7 @@ class NotionHistoryConnector:
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"CRITICAL: Failed to update page content. Original content ({block_count} blocks) "
|
"message": f"CRITICAL: Failed to update page content. Original content ({block_count} blocks) "
|
||||||
f"was deleted but new content could not be added: {str(e)}",
|
f"was deleted but new content could not be added: {e!s}",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get updated page
|
# Get updated page
|
||||||
|
|
@ -1133,7 +1133,7 @@ class NotionHistoryConnector:
|
||||||
logger.error(f"Unexpected error updating Notion page: {e}")
|
logger.error(f"Unexpected error updating Notion page: {e}")
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"Failed to update Notion page: {str(e)}",
|
"message": f"Failed to update Notion page: {e!s}",
|
||||||
}
|
}
|
||||||
|
|
||||||
async def delete_page(self, page_id: str) -> dict[str, Any]:
|
async def delete_page(self, page_id: str) -> dict[str, Any]:
|
||||||
|
|
@ -1186,5 +1186,5 @@ class NotionHistoryConnector:
|
||||||
logger.error(f"Unexpected error deleting Notion page: {e}")
|
logger.error(f"Unexpected error deleting Notion page: {e}")
|
||||||
return {
|
return {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"Failed to delete Notion page: {str(e)}",
|
"message": f"Failed to delete Notion page: {e!s}",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue