import * as z from "zod" import { defineAction } from "../../../automation/actions" import { getGmailApi } from "@automate.ax/integration-contracts/gmail" import { GMAIL_READ_REQUIREMENT } from "../lib/scopes" import { THREAD_IDENTIFIER_SCHEMA } from "@automate.ax/integration-contracts/gmail" /** * Searches Gmail threads using Gmail's standard query syntax. * * Pagination is handled internally until the requested total limit is reached. */ export const searchGmailThreads = defineAction("Search Gmail threads") .describe("Searches Gmail and returns matching thread IDs.") .account("google", GMAIL_READ_REQUIREMENT) .input( z.object({ /** Whether threads in Spam and Trash may match. */ includeSpamTrash: z.boolean().optional(), /** Label IDs that every returned thread must carry. */ labelIds: z.string().min(1).array().optional(), /** Maximum total results returned across internally fetched pages. */ limit: z.number().int().min(1).max(10_000).optional(), /** Standard Gmail search-box query. */ query: z.string().optional(), }), ) .output(THREAD_IDENTIFIER_SCHEMA.array()) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { const gmailApi = getGmailApi(account.secret) const limit = input.limit ?? 100 const threads: { threadId: string }[] = [] let pageToken: string | undefined do { const { data } = await gmailApi.users.threads.list({ includeSpamTrash: input.includeSpamTrash ?? false, labelIds: input.labelIds, maxResults: Math.min(500, limit - threads.length), pageToken, q: input.query, userId: "me", }) threads.push( ...(data.threads ?? []).flatMap((thread) => thread.id ? [{ threadId: thread.id }] : [], ), ) pageToken = data.nextPageToken ?? undefined } while (pageToken && threads.length < limit) return threads.slice(0, limit) })