EmailAgentwithMemory / app /tools /email_writing_agent_tools.py
Gaykar's picture
made changes in tools and graph
57d78b2
from langgraph.types import interrupt
from googleapiclient.errors import HttpError
from app.schemas.email_writing_agent_tools_schema import CreateDraftSchema, SendDraftSchema
from langchain.tools import tool
from langchain_google_community import GmailToolkit
from typing import Annotated, Union
from langchain_core.tools import InjectedToolCallId, tool
from langchain.tools import ToolRuntime
from langgraph.types import Command
from langchain_core.messages import SystemMessage, HumanMessage,ToolMessage,AIMessage,BaseMessage
from langgraph.graph import END
@tool(args_schema=CreateDraftSchema)
def create_gmail_draft(
to: Union[str, list],
subject: str,
body: str,
tool_call_id: Annotated[str, InjectedToolCallId] # Injected ID
):
"""Creates a new Gmail draft after human approval."""
if isinstance(to, list):
to = str(to[0]) if len(to) > 0 else "ERROR"
if to == "ERROR":
return "ERROR: 'to' parameter is empty."
# 1. Human-in-the-loop Interrupt
response = interrupt({
"action": "review_draft",
"data": {"to": to, "subject": subject, "body": body}
})
toolkit = GmailToolkit()
draft_tool = [t for t in toolkit.get_tools() if t.name == "create_gmail_draft"][0]
# 2. Handle Logic
if response.get("status") == "approved":
reply = draft_tool.invoke({"message": body, "to": [to], "subject": subject})
try:
draft_id = reply.split(":")[1].strip()
content = f"Draft created. User You MUST confirm before calling send_draft()."
# UPDATE STATE: Save draft_id directly
return Command(
update={
"draft_id": draft_id,
"reply_subject": subject,
"reply_email_body": body,
"messages": [ToolMessage(content, tool_call_id=tool_call_id)]
},goto=END
)
except IndexError:
return f"Draft created, but response parsing failed: {reply}"
else:
feedback = response.get("feedback", "User rejected.")
return f"DRAFT REJECTED BY USER. Feedback: {feedback}. Please rewrite."
#---------------------------------------------------------------------------
def send_draft(
tool_call_id: Annotated[str, InjectedToolCallId],runtime: ToolRuntime # Injected ID
):
"""Sends a finalized Gmail draft by its ID."""
try:
toolkit = GmailToolkit()
result = toolkit.api_resource.users().drafts().send(
userId="me", body={"id": runtime.state["draft_id"]}
).execute()
sent_id = result['id']
content = f"SUCCESS: Sent! a Gmail"
# UPDATE STATE: Save sent_message_id directly
return Command(
update={
"sent_message_id": sent_id,
"messages": [ToolMessage(content, tool_call_id=tool_call_id)]
}
)
except HttpError as error:
error_msg = f"ERROR: {error}"
return Command(
update={"messages": [ToolMessage(error_msg, tool_call_id=tool_call_id)]}
)
email_writing_agent_tools = [
create_gmail_draft,
send_draft
]