feat: add update functionality for Gmail drafts

- Introduced a new tool to update existing Gmail drafts, allowing users to modify draft content, recipients, and subject lines.
- Updated the Gmail tools registry to include the new update_gmail_draft tool.
- Enhanced the GmailKBSyncService to support draft ID handling during synchronization.
- Added UI components for the update draft functionality in the web application, improving user interaction with Gmail drafts.
This commit is contained in:
Anish Sarkar 2026-03-20 23:50:27 +05:30
parent 5e23949af6
commit 85462675a0
9 changed files with 1092 additions and 10 deletions

View file

@ -31,6 +31,7 @@ class GmailKBSyncService:
connector_id: int,
search_space_id: int,
user_id: str,
draft_id: str | None = None,
) -> dict:
from app.tasks.connector_indexers.base import (
check_document_by_unique_identifier,
@ -103,18 +104,22 @@ class GmailKBSyncService:
chunks = await create_document_chunks(indexable_content)
now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
doc_metadata = {
"message_id": message_id,
"thread_id": thread_id,
"subject": subject,
"sender": sender,
"date": date_str,
"connector_id": connector_id,
"indexed_at": now_str,
}
if draft_id:
doc_metadata["draft_id"] = draft_id
document = Document(
title=subject,
document_type=DocumentType.GOOGLE_GMAIL_CONNECTOR,
document_metadata={
"message_id": message_id,
"thread_id": thread_id,
"subject": subject,
"sender": sender,
"date": date_str,
"connector_id": connector_id,
"indexed_at": now_str,
},
document_metadata=doc_metadata,
content=summary_content,
content_hash=content_hash,
unique_identifier_hash=unique_hash,

View file

@ -237,6 +237,44 @@ class GmailToolMetadataService:
return {"accounts": accounts_with_status}
async def get_update_context(
self, search_space_id: int, user_id: str, email_ref: str
) -> dict:
document, connector = await self._resolve_email(
search_space_id, user_id, email_ref
)
if not document or not connector:
return {
"error": (
f"Draft '{email_ref}' not found in your indexed Gmail messages. "
"This could mean: (1) the draft doesn't exist, "
"(2) it hasn't been indexed yet, "
"or (3) the subject is different. "
"Please check the exact draft subject in Gmail."
)
}
account = GmailAccount.from_connector(connector)
message = GmailMessage.from_document(document)
acc_dict = account.to_dict()
auth_expired = await self._check_account_health(connector.id)
acc_dict["auth_expired"] = auth_expired
if auth_expired:
await self._persist_auth_expired(connector.id)
result = {
"account": acc_dict,
"email": message.to_dict(),
}
meta = document.document_metadata or {}
if meta.get("draft_id"):
result["draft_id"] = meta["draft_id"]
return result
async def get_trash_context(
self, search_space_id: int, user_id: str, email_ref: str
) -> dict: