Skip to content

Commit 4e262a0

Browse files
committed
Slack and Gmail webhook support; initial Gmail tool
1 parent d6f6a08 commit 4e262a0

File tree

8 files changed

+1128
-11
lines changed

8 files changed

+1128
-11
lines changed

.changeset/flat-moments-divide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@plotday/agent": patch
3+
---
4+
5+
Added: Slack and Gmail webhook support

builder/src/tools/network.ts

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ITool } from "..";
2+
import { type AuthProvider, type Authorization } from "./integrations";
23

34
/**
45
* Represents an incoming webhook request.
@@ -125,35 +126,68 @@ export abstract class Network extends ITool {
125126
* Generates a unique HTTP endpoint that will invoke the callback function
126127
* when requests are received. The callback receives the WebhookRequest plus any extraArgs.
127128
*
128-
* For provider-specific webhooks (e.g., Slack), use the provider and authorization
129-
* parameters to enable automatic routing based on provider-specific identifiers.
129+
* **Provider-Specific Behavior:**
130+
* - **Slack**: Uses provider-specific routing via team_id. Requires `authorization` parameter.
131+
* - **Gmail** (Google with Gmail scopes): Returns a Google Pub/Sub topic name instead of a webhook URL.
132+
* The topic name (e.g., "projects/plot-prod/topics/gmail-webhook-abc123") should be passed
133+
* to the Gmail API's `users.watch` endpoint. Requires `authorization` parameter with Gmail scopes.
134+
* - **Default**: Returns a standard webhook URL for all other cases.
130135
*
131136
* @param options - Webhook creation options
132137
* @param options.callback - Function receiving (request, ...extraArgs)
133138
* @param options.extraArgs - Additional arguments to pass to the callback (type-checked)
134139
* @param options.provider - Optional provider for provider-specific webhook routing
135-
* @param options.authorization - Optional authorization for provider-specific webhooks (required for Slack)
136-
* @returns Promise resolving to the webhook URL
140+
* @param options.authorization - Optional authorization for provider-specific webhooks (required for Slack and Gmail)
141+
* @returns Promise resolving to the webhook URL, or for Gmail, a Pub/Sub topic name
142+
*
143+
* @example
144+
* ```typescript
145+
* // Gmail webhook - returns Pub/Sub topic name
146+
* const topicName = await this.tools.network.createWebhook({
147+
* callback: this.onGmailNotification,
148+
* provider: AuthProvider.Google,
149+
* authorization: gmailAuth,
150+
* extraArgs: ["inbox"]
151+
* });
152+
* // topicName: "projects/plot-prod/topics/gmail-webhook-abc123"
153+
*
154+
* // Pass topic name to Gmail API
155+
* await gmailApi.users.watch({
156+
* userId: 'me',
157+
* requestBody: {
158+
* topicName: topicName, // Use the returned topic name
159+
* labelIds: ['INBOX']
160+
* }
161+
* });
162+
* ```
137163
*/
138-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
139164
abstract createWebhook<
140165
TCallback extends (request: WebhookRequest, ...args: any[]) => any
141166
>(options: {
142167
callback: TCallback;
143168
extraArgs?: TCallback extends (req: any, ...rest: infer R) => any ? R : [];
144-
provider?: any; // AuthProvider from integrations, but we can't import it here
145-
authorization?: any; // Authorization from integrations
169+
provider?: AuthProvider;
170+
authorization?: Authorization;
146171
}): Promise<string>;
147172

148173
/**
149174
* Deletes an existing webhook endpoint.
150175
*
151-
* Removes the webhook endpoint and stops processing requests to that URL.
152-
* Any subsequent requests to the deleted webhook will return 404.
176+
* Removes the webhook endpoint and stops processing requests.
177+
* Works with all webhook types (standard, Slack, and Gmail).
178+
*
179+
* **For Gmail webhooks:** Also deletes the associated Google Pub/Sub topic and subscription.
180+
*
181+
* **For Slack webhooks:** Removes the callback registration for the specific team.
182+
*
183+
* **For standard webhooks:** Removes the webhook endpoint. Any subsequent requests
184+
* to the deleted webhook will return 404.
153185
*
154-
* @param url - The webhook URL to delete
186+
* @param url - The webhook identifier returned from `createWebhook()`.
187+
* This can be a URL (standard webhooks), a Pub/Sub topic name (Gmail),
188+
* or an opaque identifier (Slack). Always pass the exact value returned
189+
* from `createWebhook()`.
155190
* @returns Promise that resolves when the webhook is deleted
156191
*/
157-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
158192
abstract deleteWebhook(url: string): Promise<void>;
159193
}

pnpm-lock.yaml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/gmail/package.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"name": "@plotday/tool-gmail",
3+
"displayName": "Gmail",
4+
"description": "Sync with Gmail inbox and messages",
5+
"author": "Plot <team@plot.day> (https://plot.day)",
6+
"license": "MIT",
7+
"version": "0.1.0",
8+
"type": "module",
9+
"main": "./dist/index.js",
10+
"types": "./dist/index.d.ts",
11+
"exports": {
12+
".": {
13+
"types": "./dist/index.d.ts",
14+
"default": "./dist/index.js"
15+
}
16+
},
17+
"files": [
18+
"dist",
19+
"README.md",
20+
"LICENSE"
21+
],
22+
"scripts": {
23+
"build": "tsc",
24+
"clean": "rm -rf dist"
25+
},
26+
"dependencies": {
27+
"@plotday/agent": "workspace:^"
28+
},
29+
"devDependencies": {
30+
"typescript": "^5.9.3"
31+
},
32+
"repository": {
33+
"type": "git",
34+
"url": "https://github.com/plotday/plot.git",
35+
"directory": "tools/gmail"
36+
},
37+
"homepage": "https://plot.day",
38+
"bugs": {
39+
"url": "https://github.com/plotday/plot/issues"
40+
},
41+
"keywords": [
42+
"plot",
43+
"agent",
44+
"tool",
45+
"gmail",
46+
"messaging",
47+
"email"
48+
],
49+
"publishConfig": {
50+
"access": "public"
51+
}
52+
}

0 commit comments

Comments
 (0)