mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-30 11:26:24 +02:00
refactor: replace interrupt calls with request_approval utility in Linear and Notion tools
Updated the create, delete, and update functions in Linear and Notion tools to utilize the new request_approval utility for handling user approvals. This change improves code consistency and simplifies decision handling by directly merging parameters from the approval response.
This commit is contained in:
parent
4875fd9211
commit
8d8ba6cbe8
6 changed files with 114 additions and 296 deletions
|
|
@ -2,7 +2,7 @@ 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 app.agents.new_chat.tools.hitl import request_approval
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.connectors.linear_connector import LinearAPIError, LinearConnector
|
from app.connectors.linear_connector import LinearAPIError, LinearConnector
|
||||||
|
|
@ -94,65 +94,37 @@ def create_create_linear_issue_tool(
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(f"Requesting approval for creating Linear issue: '{title}'")
|
logger.info(f"Requesting approval for creating Linear issue: '{title}'")
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="linear_issue_creation",
|
||||||
"type": "linear_issue_creation",
|
tool_name="create_linear_issue",
|
||||||
"action": {
|
params={
|
||||||
"tool": "create_linear_issue",
|
"title": title,
|
||||||
"params": {
|
"description": description,
|
||||||
"title": title,
|
"team_id": None,
|
||||||
"description": description,
|
"state_id": None,
|
||||||
"team_id": None,
|
"assignee_id": None,
|
||||||
"state_id": None,
|
"priority": None,
|
||||||
"assignee_id": None,
|
"label_ids": [],
|
||||||
"priority": None,
|
"connector_id": connector_id,
|
||||||
"label_ids": [],
|
},
|
||||||
"connector_id": connector_id,
|
context=context,
|
||||||
},
|
|
||||||
},
|
|
||||||
"context": context,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
decisions_raw = (
|
if result.rejected:
|
||||||
approval.get("decisions", []) if isinstance(approval, dict) else []
|
|
||||||
)
|
|
||||||
decisions = (
|
|
||||||
decisions_raw if isinstance(decisions_raw, list) else [decisions_raw]
|
|
||||||
)
|
|
||||||
decisions = [d for d in decisions if isinstance(d, dict)]
|
|
||||||
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("Linear issue creation rejected by user")
|
logger.info("Linear issue creation rejected by user")
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The issue was not created. Do not ask again or suggest alternatives.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
final_params: dict[str, Any] = {}
|
final_title = result.params.get("title", title)
|
||||||
edited_action = decision.get("edited_action")
|
final_description = result.params.get("description", description)
|
||||||
if isinstance(edited_action, dict):
|
final_team_id = result.params.get("team_id")
|
||||||
edited_args = edited_action.get("args")
|
final_state_id = result.params.get("state_id")
|
||||||
if isinstance(edited_args, dict):
|
final_assignee_id = result.params.get("assignee_id")
|
||||||
final_params = edited_args
|
final_priority = result.params.get("priority")
|
||||||
elif isinstance(decision.get("args"), dict):
|
final_label_ids = result.params.get("label_ids") or []
|
||||||
final_params = decision["args"]
|
final_connector_id = result.params.get("connector_id", connector_id)
|
||||||
|
|
||||||
final_title = final_params.get("title", title)
|
|
||||||
final_description = final_params.get("description", description)
|
|
||||||
final_team_id = final_params.get("team_id")
|
|
||||||
final_state_id = final_params.get("state_id")
|
|
||||||
final_assignee_id = final_params.get("assignee_id")
|
|
||||||
final_priority = final_params.get("priority")
|
|
||||||
final_label_ids = final_params.get("label_ids") or []
|
|
||||||
final_connector_id = final_params.get("connector_id", connector_id)
|
|
||||||
|
|
||||||
if not final_title or not final_title.strip():
|
if not final_title or not final_title.strip():
|
||||||
logger.error("Title is empty or contains only whitespace")
|
logger.error("Title is empty or contains only whitespace")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ 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 app.agents.new_chat.tools.hitl import request_approval
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.connectors.linear_connector import LinearAPIError, LinearConnector
|
from app.connectors.linear_connector import LinearAPIError, LinearConnector
|
||||||
|
|
@ -114,57 +114,29 @@ def create_delete_linear_issue_tool(
|
||||||
f"Requesting approval for deleting Linear issue: '{issue_ref}' "
|
f"Requesting approval for deleting Linear issue: '{issue_ref}' "
|
||||||
f"(id={issue_id}, delete_from_kb={delete_from_kb})"
|
f"(id={issue_id}, delete_from_kb={delete_from_kb})"
|
||||||
)
|
)
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="linear_issue_deletion",
|
||||||
"type": "linear_issue_deletion",
|
tool_name="delete_linear_issue",
|
||||||
"action": {
|
params={
|
||||||
"tool": "delete_linear_issue",
|
"issue_id": issue_id,
|
||||||
"params": {
|
"connector_id": connector_id_from_context,
|
||||||
"issue_id": issue_id,
|
"delete_from_kb": delete_from_kb,
|
||||||
"connector_id": connector_id_from_context,
|
},
|
||||||
"delete_from_kb": delete_from_kb,
|
context=context,
|
||||||
},
|
|
||||||
},
|
|
||||||
"context": context,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
decisions_raw = (
|
if result.rejected:
|
||||||
approval.get("decisions", []) if isinstance(approval, dict) else []
|
|
||||||
)
|
|
||||||
decisions = (
|
|
||||||
decisions_raw if isinstance(decisions_raw, list) else [decisions_raw]
|
|
||||||
)
|
|
||||||
decisions = [d for d in decisions if isinstance(d, dict)]
|
|
||||||
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("Linear issue deletion rejected by user")
|
logger.info("Linear issue deletion rejected by user")
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The issue was not deleted. Do not ask again or suggest alternatives.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
edited_action = decision.get("edited_action")
|
final_issue_id = result.params.get("issue_id", issue_id)
|
||||||
final_params: dict[str, Any] = {}
|
final_connector_id = result.params.get(
|
||||||
if isinstance(edited_action, dict):
|
|
||||||
edited_args = edited_action.get("args")
|
|
||||||
if isinstance(edited_args, dict):
|
|
||||||
final_params = edited_args
|
|
||||||
elif isinstance(decision.get("args"), dict):
|
|
||||||
final_params = decision["args"]
|
|
||||||
|
|
||||||
final_issue_id = final_params.get("issue_id", issue_id)
|
|
||||||
final_connector_id = final_params.get(
|
|
||||||
"connector_id", connector_id_from_context
|
"connector_id", connector_id_from_context
|
||||||
)
|
)
|
||||||
final_delete_from_kb = final_params.get("delete_from_kb", delete_from_kb)
|
final_delete_from_kb = result.params.get("delete_from_kb", delete_from_kb)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Deleting Linear issue with final params: issue_id={final_issue_id}, "
|
f"Deleting Linear issue with final params: issue_id={final_issue_id}, "
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ 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 app.agents.new_chat.tools.hitl import request_approval
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.connectors.linear_connector import LinearAPIError, LinearConnector
|
from app.connectors.linear_connector import LinearAPIError, LinearConnector
|
||||||
|
|
@ -130,69 +130,41 @@ def create_update_linear_issue_tool(
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Requesting approval for updating Linear issue: '{issue_ref}' (id={issue_id})"
|
f"Requesting approval for updating Linear issue: '{issue_ref}' (id={issue_id})"
|
||||||
)
|
)
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="linear_issue_update",
|
||||||
"type": "linear_issue_update",
|
tool_name="update_linear_issue",
|
||||||
"action": {
|
params={
|
||||||
"tool": "update_linear_issue",
|
"issue_id": issue_id,
|
||||||
"params": {
|
"document_id": document_id,
|
||||||
"issue_id": issue_id,
|
"new_title": new_title,
|
||||||
"document_id": document_id,
|
"new_description": new_description,
|
||||||
"new_title": new_title,
|
"new_state_id": new_state_id,
|
||||||
"new_description": new_description,
|
"new_assignee_id": new_assignee_id,
|
||||||
"new_state_id": new_state_id,
|
"new_priority": new_priority,
|
||||||
"new_assignee_id": new_assignee_id,
|
"new_label_ids": new_label_ids,
|
||||||
"new_priority": new_priority,
|
"connector_id": connector_id_from_context,
|
||||||
"new_label_ids": new_label_ids,
|
},
|
||||||
"connector_id": connector_id_from_context,
|
context=context,
|
||||||
},
|
|
||||||
},
|
|
||||||
"context": context,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
decisions_raw = (
|
if result.rejected:
|
||||||
approval.get("decisions", []) if isinstance(approval, dict) else []
|
|
||||||
)
|
|
||||||
decisions = (
|
|
||||||
decisions_raw if isinstance(decisions_raw, list) else [decisions_raw]
|
|
||||||
)
|
|
||||||
decisions = [d for d in decisions if isinstance(d, dict)]
|
|
||||||
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("Linear issue update rejected by user")
|
logger.info("Linear issue update rejected by user")
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The issue was not updated. Do not ask again or suggest alternatives.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
edited_action = decision.get("edited_action")
|
final_issue_id = result.params.get("issue_id", issue_id)
|
||||||
final_params: dict[str, Any] = {}
|
final_document_id = result.params.get("document_id", document_id)
|
||||||
if isinstance(edited_action, dict):
|
final_new_title = result.params.get("new_title", new_title)
|
||||||
edited_args = edited_action.get("args")
|
final_new_description = result.params.get("new_description", new_description)
|
||||||
if isinstance(edited_args, dict):
|
final_new_state_id = result.params.get("new_state_id", new_state_id)
|
||||||
final_params = edited_args
|
final_new_assignee_id = result.params.get("new_assignee_id", new_assignee_id)
|
||||||
elif isinstance(decision.get("args"), dict):
|
final_new_priority = result.params.get("new_priority", new_priority)
|
||||||
final_params = decision["args"]
|
final_new_label_ids: list[str] | None = result.params.get(
|
||||||
|
|
||||||
final_issue_id = final_params.get("issue_id", issue_id)
|
|
||||||
final_document_id = final_params.get("document_id", document_id)
|
|
||||||
final_new_title = final_params.get("new_title", new_title)
|
|
||||||
final_new_description = final_params.get("new_description", new_description)
|
|
||||||
final_new_state_id = final_params.get("new_state_id", new_state_id)
|
|
||||||
final_new_assignee_id = final_params.get("new_assignee_id", new_assignee_id)
|
|
||||||
final_new_priority = final_params.get("new_priority", new_priority)
|
|
||||||
final_new_label_ids: list[str] | None = final_params.get(
|
|
||||||
"new_label_ids", new_label_ids
|
"new_label_ids", new_label_ids
|
||||||
)
|
)
|
||||||
final_connector_id = final_params.get(
|
final_connector_id = result.params.get(
|
||||||
"connector_id", connector_id_from_context
|
"connector_id", connector_id_from_context
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ 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 app.agents.new_chat.tools.hitl import request_approval
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.connectors.notion_history import NotionAPIError, NotionHistoryConnector
|
from app.connectors.notion_history import NotionAPIError, NotionHistoryConnector
|
||||||
|
|
@ -99,61 +99,29 @@ def create_create_notion_page_tool(
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(f"Requesting approval for creating Notion page: '{title}'")
|
logger.info(f"Requesting approval for creating Notion page: '{title}'")
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="notion_page_creation",
|
||||||
"type": "notion_page_creation",
|
tool_name="create_notion_page",
|
||||||
"action": {
|
params={
|
||||||
"tool": "create_notion_page",
|
"title": title,
|
||||||
"params": {
|
"content": content,
|
||||||
"title": title,
|
"parent_page_id": None,
|
||||||
"content": content,
|
"connector_id": connector_id,
|
||||||
"parent_page_id": None,
|
},
|
||||||
"connector_id": connector_id,
|
context=context,
|
||||||
},
|
|
||||||
},
|
|
||||||
"context": context,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
decisions_raw = (
|
if result.rejected:
|
||||||
approval.get("decisions", []) if isinstance(approval, dict) else []
|
|
||||||
)
|
|
||||||
decisions = (
|
|
||||||
decisions_raw if isinstance(decisions_raw, list) else [decisions_raw]
|
|
||||||
)
|
|
||||||
decisions = [d for d in decisions if isinstance(d, dict)]
|
|
||||||
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 creation rejected by user")
|
logger.info("Notion page creation rejected by user")
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The page was not created. Do not ask again or suggest alternatives.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
edited_action = decision.get("edited_action")
|
final_title = result.params.get("title", title)
|
||||||
final_params: dict[str, Any] = {}
|
final_content = result.params.get("content", content)
|
||||||
if isinstance(edited_action, dict):
|
final_parent_page_id = result.params.get("parent_page_id")
|
||||||
edited_args = edited_action.get("args")
|
final_connector_id = result.params.get("connector_id", connector_id)
|
||||||
if isinstance(edited_args, dict):
|
|
||||||
final_params = edited_args
|
|
||||||
elif isinstance(decision.get("args"), dict):
|
|
||||||
# Some interrupt payloads place args directly on the decision.
|
|
||||||
final_params = decision["args"]
|
|
||||||
|
|
||||||
final_title = final_params.get("title", title)
|
|
||||||
final_content = final_params.get("content", content)
|
|
||||||
final_parent_page_id = final_params.get("parent_page_id")
|
|
||||||
final_connector_id = final_params.get("connector_id", connector_id)
|
|
||||||
|
|
||||||
if not final_title or not final_title.strip():
|
if not final_title or not final_title.strip():
|
||||||
logger.error("Title is empty or contains only whitespace")
|
logger.error("Title is empty or contains only whitespace")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ 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 app.agents.new_chat.tools.hitl import request_approval
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.connectors.notion_history import NotionAPIError, NotionHistoryConnector
|
from app.connectors.notion_history import NotionAPIError, NotionHistoryConnector
|
||||||
|
|
@ -114,63 +114,29 @@ def create_delete_notion_page_tool(
|
||||||
f"Requesting approval for deleting Notion page: '{page_title}' (page_id={page_id}, delete_from_kb={delete_from_kb})"
|
f"Requesting approval for deleting Notion page: '{page_title}' (page_id={page_id}, delete_from_kb={delete_from_kb})"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Request approval before deleting
|
result = request_approval(
|
||||||
approval = interrupt(
|
action_type="notion_page_deletion",
|
||||||
{
|
tool_name="delete_notion_page",
|
||||||
"type": "notion_page_deletion",
|
params={
|
||||||
"action": {
|
"page_id": page_id,
|
||||||
"tool": "delete_notion_page",
|
"connector_id": connector_id_from_context,
|
||||||
"params": {
|
"delete_from_kb": delete_from_kb,
|
||||||
"page_id": page_id,
|
},
|
||||||
"connector_id": connector_id_from_context,
|
context=context,
|
||||||
"delete_from_kb": delete_from_kb,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"context": context,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
decisions_raw = (
|
if result.rejected:
|
||||||
approval.get("decisions", []) if isinstance(approval, dict) else []
|
|
||||||
)
|
|
||||||
decisions = (
|
|
||||||
decisions_raw if isinstance(decisions_raw, list) else [decisions_raw]
|
|
||||||
)
|
|
||||||
decisions = [d for d in decisions if isinstance(d, dict)]
|
|
||||||
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")
|
logger.info("Notion page deletion rejected by user")
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The page was not deleted. Do not ask again or suggest alternatives.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extract edited action arguments (if user modified the checkbox)
|
final_page_id = result.params.get("page_id", page_id)
|
||||||
edited_action = decision.get("edited_action")
|
final_connector_id = result.params.get(
|
||||||
final_params: dict[str, Any] = {}
|
|
||||||
if isinstance(edited_action, dict):
|
|
||||||
edited_args = edited_action.get("args")
|
|
||||||
if isinstance(edited_args, dict):
|
|
||||||
final_params = edited_args
|
|
||||||
elif isinstance(decision.get("args"), dict):
|
|
||||||
# Some interrupt payloads place args directly on the decision.
|
|
||||||
final_params = decision["args"]
|
|
||||||
|
|
||||||
final_page_id = final_params.get("page_id", page_id)
|
|
||||||
final_connector_id = final_params.get(
|
|
||||||
"connector_id", connector_id_from_context
|
"connector_id", connector_id_from_context
|
||||||
)
|
)
|
||||||
final_delete_from_kb = final_params.get("delete_from_kb", delete_from_kb)
|
final_delete_from_kb = result.params.get("delete_from_kb", delete_from_kb)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Deleting Notion page with final params: page_id={final_page_id}, connector_id={final_connector_id}, delete_from_kb={final_delete_from_kb}"
|
f"Deleting Notion page with final params: page_id={final_page_id}, connector_id={final_connector_id}, delete_from_kb={final_delete_from_kb}"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ 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 app.agents.new_chat.tools.hitl import request_approval
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.connectors.notion_history import NotionAPIError, NotionHistoryConnector
|
from app.connectors.notion_history import NotionAPIError, NotionHistoryConnector
|
||||||
|
|
@ -127,59 +127,27 @@ def create_update_notion_page_tool(
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Requesting approval for updating Notion page: '{page_title}' (page_id={page_id})"
|
f"Requesting approval for updating Notion page: '{page_title}' (page_id={page_id})"
|
||||||
)
|
)
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="notion_page_update",
|
||||||
"type": "notion_page_update",
|
tool_name="update_notion_page",
|
||||||
"action": {
|
params={
|
||||||
"tool": "update_notion_page",
|
"page_id": page_id,
|
||||||
"params": {
|
"content": content,
|
||||||
"page_id": page_id,
|
"connector_id": connector_id_from_context,
|
||||||
"content": content,
|
},
|
||||||
"connector_id": connector_id_from_context,
|
context=context,
|
||||||
},
|
|
||||||
},
|
|
||||||
"context": context,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
decisions_raw = (
|
if result.rejected:
|
||||||
approval.get("decisions", []) if isinstance(approval, dict) else []
|
|
||||||
)
|
|
||||||
decisions = (
|
|
||||||
decisions_raw if isinstance(decisions_raw, list) else [decisions_raw]
|
|
||||||
)
|
|
||||||
decisions = [d for d in decisions if isinstance(d, dict)]
|
|
||||||
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 update rejected by user")
|
logger.info("Notion page update rejected by user")
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The page was not updated. Do not ask again or suggest alternatives.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
edited_action = decision.get("edited_action")
|
final_page_id = result.params.get("page_id", page_id)
|
||||||
final_params: dict[str, Any] = {}
|
final_content = result.params.get("content", content)
|
||||||
if isinstance(edited_action, dict):
|
final_connector_id = result.params.get(
|
||||||
edited_args = edited_action.get("args")
|
|
||||||
if isinstance(edited_args, dict):
|
|
||||||
final_params = edited_args
|
|
||||||
elif isinstance(decision.get("args"), dict):
|
|
||||||
# Some interrupt payloads place args directly on the decision.
|
|
||||||
final_params = decision["args"]
|
|
||||||
|
|
||||||
final_page_id = final_params.get("page_id", page_id)
|
|
||||||
final_content = final_params.get("content", content)
|
|
||||||
final_connector_id = final_params.get(
|
|
||||||
"connector_id", connector_id_from_context
|
"connector_id", connector_id_from_context
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue