From 45cdcc3c0ab6084864ad0ff672c3bb882764a640 Mon Sep 17 00:00:00 2001 From: Recoup Agent Date: Wed, 11 Mar 2026 01:54:27 +0000 Subject: [PATCH 1/2] agent: @U0AJM7X8FBR API - I want to support Resend in our current implementatio --- lib/coding-agent/__tests__/bot.test.ts | 31 ++++++++++++++++++++++++++ lib/coding-agent/bot.ts | 15 +++++++++++-- lib/coding-agent/const.ts | 4 ++++ package.json | 1 + 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 lib/coding-agent/const.ts diff --git a/lib/coding-agent/__tests__/bot.test.ts b/lib/coding-agent/__tests__/bot.test.ts index 185c2fa7..fc8412df 100644 --- a/lib/coding-agent/__tests__/bot.test.ts +++ b/lib/coding-agent/__tests__/bot.test.ts @@ -12,6 +12,12 @@ vi.mock("@chat-adapter/github", () => ({ }), })); +vi.mock("@resend/chat-sdk-adapter", () => ({ + createResendAdapter: vi.fn().mockReturnValue({ + name: "resend", + }), +})); + vi.mock("@chat-adapter/state-ioredis", () => ({ createIoRedisState: vi.fn().mockReturnValue({ connect: vi.fn(), @@ -126,4 +132,29 @@ describe("createCodingAgentBot", () => { const lastCall = vi.mocked(Chat).mock.calls.at(-1)!; expect(lastCall[0].userName).toBe("Recoup Agent"); }); + + it("creates a Chat instance with resend adapter", async () => { + const { Chat } = await import("chat"); + const { createCodingAgentBot } = await import("../bot"); + + createCodingAgentBot(); + + const lastCall = vi.mocked(Chat).mock.calls.at(-1)!; + const config = lastCall[0]; + expect(config.adapters).toHaveProperty("resend"); + }); + + it("creates Resend adapter with correct from address", async () => { + const { createResendAdapter } = await import("@resend/chat-sdk-adapter"); + const { createCodingAgentBot } = await import("../bot"); + + createCodingAgentBot(); + + expect(createResendAdapter).toHaveBeenCalledWith( + expect.objectContaining({ + fromAddress: "agent@recoupable.com", + fromName: "Recoup Agent", + }), + ); + }); }); diff --git a/lib/coding-agent/bot.ts b/lib/coding-agent/bot.ts index 4cd2db31..debe72cd 100644 --- a/lib/coding-agent/bot.ts +++ b/lib/coding-agent/bot.ts @@ -1,10 +1,12 @@ import { Chat, ConsoleLogger } from "chat"; import { SlackAdapter } from "@chat-adapter/slack"; import { createGitHubAdapter } from "@chat-adapter/github"; +import { createResendAdapter } from "@resend/chat-sdk-adapter"; import { createIoRedisState } from "@chat-adapter/state-ioredis"; import redis from "@/lib/redis/connection"; import type { CodingAgentThreadState } from "./types"; import { validateCodingAgentEnv } from "./validateEnv"; +import { CODING_AGENT_FROM_EMAIL } from "./const"; const logger = new ConsoleLogger(); @@ -40,9 +42,18 @@ export function createCodingAgentBot() { logger, }); - return new Chat<{ slack: SlackAdapter; github: ReturnType }, CodingAgentThreadState>({ + const resend = createResendAdapter({ + fromAddress: CODING_AGENT_FROM_EMAIL, + fromName: "Recoup Agent", + }); + + return new Chat<{ + slack: SlackAdapter; + github: ReturnType; + resend: ReturnType; + }, CodingAgentThreadState>({ userName: "Recoup Agent", - adapters: { slack, github }, + adapters: { slack, github, resend }, state, }); } diff --git a/lib/coding-agent/const.ts b/lib/coding-agent/const.ts new file mode 100644 index 00000000..887ec596 --- /dev/null +++ b/lib/coding-agent/const.ts @@ -0,0 +1,4 @@ +/** + * The from email address used by the coding agent for Resend emails. + */ +export const CODING_AGENT_FROM_EMAIL = "agent@recoupable.com"; diff --git a/package.json b/package.json index e2c8ba47..31369b3d 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@chat-adapter/github": "^4.15.0", "@chat-adapter/slack": "^4.15.0", "@chat-adapter/state-ioredis": "^4.15.0", + "@resend/chat-sdk-adapter": "^0.1.0", "@coinbase/cdp-sdk": "^1.38.6", "@coinbase/x402": "^0.7.3", "@composio/core": "^0.3.4", From 8855c44379774759b837fdba0ed156356d0e485e Mon Sep 17 00:00:00 2001 From: Recoup Agent Date: Wed, 11 Mar 2026 15:12:11 +0000 Subject: [PATCH 2/2] agent: address feedback --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 38caae24..0d753435 100644 --- a/README.md +++ b/README.md @@ -177,4 +177,65 @@ Set this in your `.env` (local) or in your hosting provider's environment variab ## Accessing Mainnet -To access the mainnet facilitator in Next.js, simply install and use the `@coinbase/x402` package. \ No newline at end of file +To access the mainnet facilitator in Next.js, simply install and use the `@coinbase/x402` package. + +## Testing Resend Email Integration + +The coding agent supports email conversations via Resend. To test this integration: + +### 1. Configure Environment Variables + +Ensure these environment variables are set in your `.env`: + +```bash +RESEND_API_KEY=re_your_api_key_here +# Optional: for webhook signature verification +RESEND_WEBHOOK_SECRET=whsec_your_webhook_secret_here +``` + +### 2. Set Up Resend Webhook + +In your [Resend dashboard](https://resend.com/dashboard/webhooks): + +1. Create a new webhook +2. Set the endpoint URL to: `https:///api/coding-agent/resend` +3. Select events: `email.sent`, `email.delivered`, `email.opened`, `email.clicked`, `email.bounced` +4. Copy the webhook signing secret and set it as `RESEND_WEBHOOK_SECRET` + +### 3. Send a Test Email + +Send an email to `agent@recoupable.com` with: +- **Subject**: Your request (e.g., "Fix the login bug") +- **Body**: Detailed description of what you want the coding agent to do + +The coding agent will: +1. Receive the email via Resend webhook +2. Create a new thread (same as a Slack mention) +3. Process your request +4. Reply via email with the results + +### 4. Test Reply Threading + +Reply to the agent's email to continue the conversation. The email threading uses standard `Message-ID` and `In-Reply-To` headers, so replies are automatically grouped into the same Chat SDK thread. + +### 5. Local Development with ngrok + +For local testing, use [ngrok](https://ngrok.com/) to expose your local server: + +```bash +# Terminal 1: Start the dev server +pnpm dev + +# Terminal 2: Expose via ngrok +npx ngrok http 3000 + +# Update Resend webhook URL to: https://.ngrok.io/api/coding-agent/resend +``` + +### 6. Verify in Logs + +Check the server logs for: +- `POST /api/coding-agent/resend` — Webhook received +- `Syncing monorepo submodules` — Submodule sync before changes +- `Agent completed` — Coding agent finished +- Email sent confirmation via Resend \ No newline at end of file