mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-04 13:22:41 +02:00
refactor: replace interrupt calls with request_approval utility in Jira and OneDrive tools
Updated the create, delete, and update functions in Jira and OneDrive 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
2f59fc9c72
commit
4875fd9211
5 changed files with 89 additions and 220 deletions
|
|
@ -3,7 +3,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 sqlalchemy.orm.attributes import flag_modified
|
from sqlalchemy.orm.attributes import flag_modified
|
||||||
|
|
||||||
|
|
@ -69,58 +69,32 @@ def create_create_jira_issue_tool(
|
||||||
"connector_type": "jira",
|
"connector_type": "jira",
|
||||||
}
|
}
|
||||||
|
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="jira_issue_creation",
|
||||||
"type": "jira_issue_creation",
|
tool_name="create_jira_issue",
|
||||||
"action": {
|
params={
|
||||||
"tool": "create_jira_issue",
|
"project_key": project_key,
|
||||||
"params": {
|
"summary": summary,
|
||||||
"project_key": project_key,
|
"issue_type": issue_type,
|
||||||
"summary": summary,
|
"description": description,
|
||||||
"issue_type": issue_type,
|
"priority": priority,
|
||||||
"description": description,
|
"connector_id": connector_id,
|
||||||
"priority": priority,
|
},
|
||||||
"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:
|
|
||||||
return {"status": "error", "message": "No approval decision received"}
|
|
||||||
|
|
||||||
decision = decisions[0]
|
|
||||||
decision_type = decision.get("type") or decision.get("decision_type")
|
|
||||||
|
|
||||||
if decision_type == "reject":
|
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The issue was not created.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
final_params: dict[str, Any] = {}
|
final_project_key = result.params.get("project_key", project_key)
|
||||||
edited_action = decision.get("edited_action")
|
final_summary = result.params.get("summary", summary)
|
||||||
if isinstance(edited_action, dict):
|
final_issue_type = result.params.get("issue_type", issue_type)
|
||||||
edited_args = edited_action.get("args")
|
final_description = result.params.get("description", description)
|
||||||
if isinstance(edited_args, dict):
|
final_priority = result.params.get("priority", priority)
|
||||||
final_params = edited_args
|
final_connector_id = result.params.get("connector_id", connector_id)
|
||||||
elif isinstance(decision.get("args"), dict):
|
|
||||||
final_params = decision["args"]
|
|
||||||
|
|
||||||
final_project_key = final_params.get("project_key", project_key)
|
|
||||||
final_summary = final_params.get("summary", summary)
|
|
||||||
final_issue_type = final_params.get("issue_type", issue_type)
|
|
||||||
final_description = final_params.get("description", description)
|
|
||||||
final_priority = final_params.get("priority", priority)
|
|
||||||
final_connector_id = final_params.get("connector_id", connector_id)
|
|
||||||
|
|
||||||
if not final_summary or not final_summary.strip():
|
if not final_summary or not final_summary.strip():
|
||||||
return {"status": "error", "message": "Issue summary cannot be empty."}
|
return {"status": "error", "message": "Issue summary cannot be empty."}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,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 sqlalchemy.orm.attributes import flag_modified
|
from sqlalchemy.orm.attributes import flag_modified
|
||||||
|
|
||||||
|
|
@ -71,54 +71,28 @@ def create_delete_jira_issue_tool(
|
||||||
document_id = issue_data["document_id"]
|
document_id = issue_data["document_id"]
|
||||||
connector_id_from_context = context.get("account", {}).get("id")
|
connector_id_from_context = context.get("account", {}).get("id")
|
||||||
|
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="jira_issue_deletion",
|
||||||
"type": "jira_issue_deletion",
|
tool_name="delete_jira_issue",
|
||||||
"action": {
|
params={
|
||||||
"tool": "delete_jira_issue",
|
"issue_key": issue_key,
|
||||||
"params": {
|
"connector_id": connector_id_from_context,
|
||||||
"issue_key": issue_key,
|
"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:
|
|
||||||
return {"status": "error", "message": "No approval decision received"}
|
|
||||||
|
|
||||||
decision = decisions[0]
|
|
||||||
decision_type = decision.get("type") or decision.get("decision_type")
|
|
||||||
|
|
||||||
if decision_type == "reject":
|
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The issue was not deleted.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
final_params: dict[str, Any] = {}
|
final_issue_key = result.params.get("issue_key", issue_key)
|
||||||
edited_action = decision.get("edited_action")
|
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_key = final_params.get("issue_key", issue_key)
|
|
||||||
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)
|
||||||
|
|
||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,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 sqlalchemy.orm.attributes import flag_modified
|
from sqlalchemy.orm.attributes import flag_modified
|
||||||
|
|
||||||
|
|
@ -75,60 +75,34 @@ def create_update_jira_issue_tool(
|
||||||
document_id = issue_data.get("document_id")
|
document_id = issue_data.get("document_id")
|
||||||
connector_id_from_context = context.get("account", {}).get("id")
|
connector_id_from_context = context.get("account", {}).get("id")
|
||||||
|
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="jira_issue_update",
|
||||||
"type": "jira_issue_update",
|
tool_name="update_jira_issue",
|
||||||
"action": {
|
params={
|
||||||
"tool": "update_jira_issue",
|
"issue_key": issue_key,
|
||||||
"params": {
|
"document_id": document_id,
|
||||||
"issue_key": issue_key,
|
"new_summary": new_summary,
|
||||||
"document_id": document_id,
|
"new_description": new_description,
|
||||||
"new_summary": new_summary,
|
"new_priority": new_priority,
|
||||||
"new_description": new_description,
|
"connector_id": connector_id_from_context,
|
||||||
"new_priority": new_priority,
|
},
|
||||||
"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:
|
|
||||||
return {"status": "error", "message": "No approval decision received"}
|
|
||||||
|
|
||||||
decision = decisions[0]
|
|
||||||
decision_type = decision.get("type") or decision.get("decision_type")
|
|
||||||
|
|
||||||
if decision_type == "reject":
|
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The issue was not updated.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
final_params: dict[str, Any] = {}
|
final_issue_key = result.params.get("issue_key", issue_key)
|
||||||
edited_action = decision.get("edited_action")
|
final_summary = result.params.get("new_summary", new_summary)
|
||||||
if isinstance(edited_action, dict):
|
final_description = result.params.get("new_description", new_description)
|
||||||
edited_args = edited_action.get("args")
|
final_priority = result.params.get("new_priority", new_priority)
|
||||||
if isinstance(edited_args, dict):
|
final_connector_id = result.params.get(
|
||||||
final_params = edited_args
|
|
||||||
elif isinstance(decision.get("args"), dict):
|
|
||||||
final_params = decision["args"]
|
|
||||||
|
|
||||||
final_issue_key = final_params.get("issue_key", issue_key)
|
|
||||||
final_summary = final_params.get("new_summary", new_summary)
|
|
||||||
final_description = final_params.get("new_description", new_description)
|
|
||||||
final_priority = final_params.get("new_priority", new_priority)
|
|
||||||
final_connector_id = final_params.get(
|
|
||||||
"connector_id", connector_id_from_context
|
"connector_id", connector_id_from_context
|
||||||
)
|
)
|
||||||
final_document_id = final_params.get("document_id", document_id)
|
final_document_id = result.params.get("document_id", document_id)
|
||||||
|
|
||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from pathlib import Path
|
||||||
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 sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
||||||
|
|
@ -145,54 +145,28 @@ def create_create_onedrive_file_tool(
|
||||||
"parent_folders": parent_folders,
|
"parent_folders": parent_folders,
|
||||||
}
|
}
|
||||||
|
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="onedrive_file_creation",
|
||||||
"type": "onedrive_file_creation",
|
tool_name="create_onedrive_file",
|
||||||
"action": {
|
params={
|
||||||
"tool": "create_onedrive_file",
|
"name": name,
|
||||||
"params": {
|
"content": content,
|
||||||
"name": name,
|
"connector_id": None,
|
||||||
"content": content,
|
"parent_folder_id": None,
|
||||||
"connector_id": None,
|
},
|
||||||
"parent_folder_id": None,
|
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:
|
|
||||||
return {"status": "error", "message": "No approval decision received"}
|
|
||||||
|
|
||||||
decision = decisions[0]
|
|
||||||
decision_type = decision.get("type") or decision.get("decision_type")
|
|
||||||
|
|
||||||
if decision_type == "reject":
|
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The file was not created.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
final_params: dict[str, Any] = {}
|
final_name = result.params.get("name", name)
|
||||||
edited_action = decision.get("edited_action")
|
final_content = result.params.get("content", content)
|
||||||
if isinstance(edited_action, dict):
|
final_connector_id = result.params.get("connector_id")
|
||||||
edited_args = edited_action.get("args")
|
final_parent_folder_id = result.params.get("parent_folder_id")
|
||||||
if isinstance(edited_args, dict):
|
|
||||||
final_params = edited_args
|
|
||||||
elif isinstance(decision.get("args"), dict):
|
|
||||||
final_params = decision["args"]
|
|
||||||
|
|
||||||
final_name = final_params.get("name", name)
|
|
||||||
final_content = final_params.get("content", content)
|
|
||||||
final_connector_id = final_params.get("connector_id")
|
|
||||||
final_parent_folder_id = final_params.get("parent_folder_id")
|
|
||||||
|
|
||||||
if not final_name or not final_name.strip():
|
if not final_name or not final_name.strip():
|
||||||
return {"status": "error", "message": "File name cannot be empty."}
|
return {"status": "error", "message": "File name cannot be empty."}
|
||||||
|
|
|
||||||
|
|
@ -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 import String, and_, cast, func
|
from sqlalchemy import String, and_, cast, func
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
@ -174,53 +174,26 @@ def create_delete_onedrive_file_tool(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
approval = interrupt(
|
result = request_approval(
|
||||||
{
|
action_type="onedrive_file_trash",
|
||||||
"type": "onedrive_file_trash",
|
tool_name="delete_onedrive_file",
|
||||||
"action": {
|
params={
|
||||||
"tool": "delete_onedrive_file",
|
"file_id": file_id,
|
||||||
"params": {
|
"connector_id": connector.id,
|
||||||
"file_id": file_id,
|
"delete_from_kb": delete_from_kb,
|
||||||
"connector_id": connector.id,
|
},
|
||||||
"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:
|
|
||||||
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":
|
|
||||||
return {
|
return {
|
||||||
"status": "rejected",
|
"status": "rejected",
|
||||||
"message": "User declined. The file was not trashed. Do not ask again or suggest alternatives.",
|
"message": "User declined. Do not retry or suggest alternatives.",
|
||||||
}
|
}
|
||||||
|
|
||||||
final_params: dict[str, Any] = {}
|
final_file_id = result.params.get("file_id", file_id)
|
||||||
edited_action = decision.get("edited_action")
|
final_connector_id = result.params.get("connector_id", connector.id)
|
||||||
if isinstance(edited_action, dict):
|
final_delete_from_kb = result.params.get("delete_from_kb", delete_from_kb)
|
||||||
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_file_id = final_params.get("file_id", file_id)
|
|
||||||
final_connector_id = final_params.get("connector_id", connector.id)
|
|
||||||
final_delete_from_kb = final_params.get("delete_from_kb", delete_from_kb)
|
|
||||||
|
|
||||||
if final_connector_id != connector.id:
|
if final_connector_id != connector.id:
|
||||||
result = await db_session.execute(
|
result = await db_session.execute(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue