feat: send-only Gmail integration with draft_email chat tool - #1819
Open
gabrielste1n wants to merge 1 commit into
Open
feat: send-only Gmail integration with draft_email chat tool#1819gabrielste1n wants to merge 1 commit into
gabrielste1n wants to merge 1 commit into
Conversation
Connect Gmail from Settings -> Integrations (loopback PKCE OAuth, gmail.send scope only) and ask the note chat to draft a follow-up email: a new draft_email tool composes from the note, transcript, and participants, and renders an editable email card in chat. Sending only happens when the user presses Send on the card. - Gmail OAuth + manager in the main process (net.fetch, no new deps), reusing the shared loopback flow; falls back to the calendar OAuth client - Gmail tokens encrypted at rest via secretCrypto (keychain AES-256-GCM), single-account, revoked on account deletion - draft_email tool gated on a connected Gmail account; participants from calendar events now included in the note chat context - EmailDraftCard with editable To/Cc/Subject/body, send states, and sent status persisted into the message's tool-call metadata - Forward AI-SDK tool outputs as metadata on the BYOK/local path so tool-result cards (including existing note cards) render there too - Integrations tile hidden when no OAuth client is configured; i18n for all 10 locales
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds Gmail as an integration (Settings → Integrations → Email) and a
draft_emailchat tool. In a meeting note's chat, "draft me a follow-up email" produces an editable email card — To/Cc pre-filled from the note's calendar participants, subject and body composed from the note and transcript. Pressing Send on the card sends via the Gmail API from the user's account.Design decisions
gmail.send openid emailonly — Google's sensitive tier, which requires only brand verification (no CASA security audit). No read/compose scopes anywhere.draft_emailis a pure compose step that returns the draft as tool metadata; the only send path is the user's click on the card, which goes through a dedicatedgmail-send-emailIPC handler.gmail_tokenscolumns are encrypted with the existingsecretCryptohelper (OS-keychain AES-256-GCM) — deliberately stronger than the plaintext-SQLite calendar-token precedent, since a send-capable refresh token is higher risk. Plaintext fallback only where the app already falls back (Linux without a keyring). Tokens are revoked on disconnect and on account deletion.127.0.0.1+ PKCE flow (oauthLoopbackFlow.js), samenet.fetchconventions, no new dependencies. Client credentials readGMAIL_CLIENT_ID/_SECRETwith fallback toGOOGLE_CALENDAR_CLIENT_*(same GCP client), so CI needs no changes.Notable side fix
The BYOK/local streaming path dropped tool-result
metadata(only the cloud path forwarded it), so interactive tool cards silently never rendered for BYOK users.processTextStreamingAInow forwards successful object outputs as metadata — this also un-breaks the existing note cards on BYOK.Changes
gmailOAuth.js,gmailManager.js(RFC 2822 MIME builder +messages/sendPOST), encryptedgmail_tokenstable + CRUD,gmail-*IPC handlers, lifecycle wiring, revoke on account deletiongmailConnected/gmailEmailin the settings store,draft_emailtool gated on connection, participants added to note-chat context,EmailDraftCardwith draft/sending/sent/failed states, sent state persisted into the message's tool-call metadata via a newdb-update-agent-tool-callIPCnpm run i18n:checkpasses)gmailManager(MIME framing, UTF-8 headers, send auth/error paths),gmailDatabase(encryption at rest, single-account replacement, metadata patching), anddraftEmailTool(validation, no-send contract)Testing
npm test: 2777 pass; the only 2 failures (textEditMonitorWindowBounds) fail identically on pristinemain(environment-dependent)npm run typecheck,npm run lint,npm run i18n:check: cleanmainCompanion PR
/auth/desktop-callbackthegmail_connected/gmail_errorparams. Until it deploys, test locally withVITE_OPENWHISPR_OAUTH_CALLBACK_URL.Out of scope (follow-ups)
gmail.sendto the consent screen and submit sensitive-scope verification (this flow doubles as the demo video)