Skip to content

Add Gmail tools for Interchange - #1

Open
pratikbuilds wants to merge 10 commits into
mainfrom
add-gmail-tools
Open

Add Gmail tools for Interchange#1
pratikbuilds wants to merge 10 commits into
mainfrom
add-gmail-tools

Conversation

@pratikbuilds

@pratikbuilds pratikbuilds commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a focused Gmail REST client with strict response handling
  • expose ten Interchange Gmail tools with approval-gated mutations
  • add separate read and mutation live suites with safe cleanup

Live Gmail validation

The full live suite passed against a dedicated Gmail fixture account and exercised every exposed tool:

  • gmail_search_threads finds the one-message fixture thread.
  • gmail_get_thread and gmail_get_message retrieve fixture metadata.
  • gmail_list_labels lists mailbox labels.
  • gmail_create_draft and gmail_list_drafts create and find a disposable draft; the suite deletes it during cleanup.
  • gmail_label_message and gmail_unlabel_message add and remove STARRED on the fixture message.
  • gmail_label_thread and gmail_unlabel_thread add and remove STARRED across the fixture thread, then restore its original label state.

The live suite never sends email.

Verification

  • bun run test — 31 passed
  • bun run typecheck
  • bun run typecheck:live
  • bun run build
  • full Gmail live suite — 10 passed, 0 failed

@TheGreatAxios
TheGreatAxios self-requested a review August 24, 2026 22:13

@TheGreatAxios TheGreatAxios left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: add-gmail-tools -> main

Verdict: Comment (no blocking defects). Well-structured, defensively-written PR with real test coverage. One developer-experience bug worth fixing before/after merge, plus non-blocking observations.

Verification performed

  • bun run typecheck: clean (exit 0)
  • bun run test (scoped script): 31 pass / 0 fail
  • Bare bun test (the command README documents): exit 1 out of the box — see Finding 1
  • Commits audited: 5, all on-scope for Gmail tooling; no stray/binary changes beyond expected bun.lock

Findings

1. [Low] Fresh contributor following the README gets a failing suite.
README documents bare bun test, which sweeps in tests/live/gmail.read.e2e.test.ts; its opt-in gate throws rather than skips (tests/live/gmail.read.e2e.test.ts:7-12), so bun test exits 1 with no env config. The sibling mutations suite gates correctly with test.skip (tests/live/gmail.mutations.e2e.test.ts:10-14). Two consistent fixes: make the read gate skip like its sibling, or document bun run test (the scoped package.json script already excludes both live e2e files).

2. [Observation] Failed client resolution is memoized.
In createGmailTools, clientPromise ??= caches the promise even when the first credential resolution rejects (src/tools/create-tools.ts:398-411). Every later call keeps returning the stale rejection until dispose/recreate, even if credentials become resolvable again. Fail-closed is correct; consider clearing clientPromise on rejection so recovery is possible.

3. [Observation] Query-filtered draft listing scans all drafts.
listDraftsForQuery pages through the entire draft collection at pageSize: 500 on every call (src/tools/create-tools.ts:157-169), independent of the requested page size. Fine at typical mailbox scale; worth an early-exit once enough matches are collected for the requested page.

4. [Observation] Thread search fan-out.
gmail_search_threads issues one getThread per result thread concurrently, capped at 50 by the input schema. Inherent to Gmail's API shape; just noting the latency profile (up to 51 upstream requests per tool call).

5. [Question] resultCountEstimate is stringified.
String(response.resultSizeEstimate) turns Google's numeric field into a string (src/tools/create-tools.ts:220). Intentional Interchange-side contract, or accidental?

Strengths

  • Strict arktype inputs ("+": "reject") across every tool, with generated JSON Schemas and a runtime definitions-vs-handlers invariant check.
  • CRLF injection guards on all header-bound values, including reply references (src/tools/drafts.ts); quote-aware RFC 5322 recipient splitting with dedicated tests (src/tools/models.ts).
  • SSRF guard rejecting absolute request paths at the client boundary; encodeURIComponent on all IDs; per-request timeout composed with caller abort signals.
  • Live-test OAuth harness done right: loopback callback with state validation and timeout, token files written 0600 in 0700 dirs, bearer pinned to the Gmail origin, 401 refresh limited to idempotent methods, concurrent-refresh dedupe.
  • Every mailbox mutation requires approval (MUTATING_TOOL_NAMES -> approval: "ask"), and a unit test enforces it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants