From 43af0fa65865bea6d290c28d6eb3e397007484fc Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 18 Jun 2026 15:38:15 -0500 Subject: [PATCH 1/2] feat: add X (Twitter) + LinkedIn to the Composio connector whitelist (chat#1793) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand the existing whitelist pattern to two new platforms — no architecture changes: - SUPPORTED_TOOLKITS (getConnectors.ts) + ENABLED_TOOLKITS (getComposioTools.ts) - CONNECTOR_DISPLAY_NAMES: twitter → "X (Twitter)", linkedin → "LinkedIn" - buildAuthConfigs() reads COMPOSIO_TWITTER_AUTH_CONFIG_ID + COMPOSIO_LINKEDIN_AUTH_CONFIG_ID - document both env vars in .env.example TDD: new buildAuthConfigs unit + expanded getConnectors / handler / ENABLED_TOOLKITS assertions, RED before GREEN. Full lib/composio suite green (157 tests). Implements the contract from docs#244. Co-Authored-By: Claude Opus 4.8 (1M context) --- .env.example | 2 + .../__tests__/buildAuthConfigs.test.ts | 48 +++++++++++++++++++ .../__tests__/getConnectors.test.ts | 22 ++++++++- .../__tests__/getConnectorsHandler.test.ts | 2 + lib/composio/connectors/buildAuthConfigs.ts | 6 +++ lib/composio/connectors/getConnectors.ts | 2 + .../connectors/getConnectorsHandler.ts | 2 + .../__tests__/getComposioTools.test.ts | 9 +++- lib/composio/toolRouter/getComposioTools.ts | 2 + 9 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 lib/composio/connectors/__tests__/buildAuthConfigs.test.ts diff --git a/.env.example b/.env.example index 9d6de84d9..80bca6864 100644 --- a/.env.example +++ b/.env.example @@ -34,6 +34,8 @@ COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID= COMPOSIO_GOOGLE_SHEETS_AUTH_CONFIG_ID= COMPOSIO_GOOGLE_DOCS_AUTH_CONFIG_ID= COMPOSIO_GOOGLE_DRIVE_AUTH_CONFIG_ID= +COMPOSIO_TWITTER_AUTH_CONFIG_ID= +COMPOSIO_LINKEDIN_AUTH_CONFIG_ID= # Slack (coding agent) SLACK_BOT_TOKEN= diff --git a/lib/composio/connectors/__tests__/buildAuthConfigs.test.ts b/lib/composio/connectors/__tests__/buildAuthConfigs.test.ts new file mode 100644 index 000000000..451dc92ed --- /dev/null +++ b/lib/composio/connectors/__tests__/buildAuthConfigs.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { buildAuthConfigs } from "../buildAuthConfigs"; + +const AUTH_CONFIG_ENV_KEYS = [ + "COMPOSIO_TIKTOK_AUTH_CONFIG_ID", + "COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID", + "COMPOSIO_GOOGLE_SHEETS_AUTH_CONFIG_ID", + "COMPOSIO_GOOGLE_DOCS_AUTH_CONFIG_ID", + "COMPOSIO_GOOGLE_DRIVE_AUTH_CONFIG_ID", + "COMPOSIO_YOUTUBE_AUTH_CONFIG_ID", + "COMPOSIO_TWITTER_AUTH_CONFIG_ID", + "COMPOSIO_LINKEDIN_AUTH_CONFIG_ID", +]; + +describe("buildAuthConfigs", () => { + let saved: Record; + + beforeEach(() => { + // Snapshot then clear every auth-config env var so the test is isolated + // from whatever .env.local provides. + saved = {}; + for (const key of AUTH_CONFIG_ENV_KEYS) { + saved[key] = process.env[key]; + delete process.env[key]; + } + }); + + afterEach(() => { + for (const key of AUTH_CONFIG_ENV_KEYS) { + if (saved[key] === undefined) delete process.env[key]; + else process.env[key] = saved[key]; + } + }); + + it("returns undefined when no auth-config env vars are set", () => { + expect(buildAuthConfigs()).toBeUndefined(); + }); + + it("reads the Twitter and LinkedIn auth configs from env", () => { + process.env.COMPOSIO_TWITTER_AUTH_CONFIG_ID = "ac_twitter_123"; + process.env.COMPOSIO_LINKEDIN_AUTH_CONFIG_ID = "ac_linkedin_456"; + + expect(buildAuthConfigs()).toEqual({ + twitter: "ac_twitter_123", + linkedin: "ac_linkedin_456", + }); + }); +}); diff --git a/lib/composio/connectors/__tests__/getConnectors.test.ts b/lib/composio/connectors/__tests__/getConnectors.test.ts index 762c07e07..cf0f50b06 100644 --- a/lib/composio/connectors/__tests__/getConnectors.test.ts +++ b/lib/composio/connectors/__tests__/getConnectors.test.ts @@ -37,7 +37,16 @@ describe("getConnectors", () => { expect(getComposioClient).toHaveBeenCalled(); expect(mockComposio.create).toHaveBeenCalledWith("account-123", { - toolkits: ["googlesheets", "googledrive", "googledocs", "tiktok", "instagram", "youtube"], + toolkits: [ + "googlesheets", + "googledrive", + "googledocs", + "tiktok", + "instagram", + "youtube", + "twitter", + "linkedin", + ], }); expect(result).toEqual([ { @@ -92,7 +101,16 @@ describe("getConnectors", () => { await getConnectors("account-123"); expect(mockComposio.create).toHaveBeenCalledWith("account-123", { - toolkits: ["googlesheets", "googledrive", "googledocs", "tiktok", "instagram", "youtube"], + toolkits: [ + "googlesheets", + "googledrive", + "googledocs", + "tiktok", + "instagram", + "youtube", + "twitter", + "linkedin", + ], authConfigs: { tiktok: "ac_tiktok_123", instagram: "ac_instagram_456", diff --git a/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts b/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts index d6c3fe31f..bc68d0af6 100644 --- a/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts +++ b/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts @@ -72,6 +72,8 @@ describe("getConnectorsHandler", () => { googlesheets: "Google Sheets", googledrive: "Google Drive", googledocs: "Google Docs", + twitter: "X (Twitter)", + linkedin: "LinkedIn", }, }); }); diff --git a/lib/composio/connectors/buildAuthConfigs.ts b/lib/composio/connectors/buildAuthConfigs.ts index 2c31d571a..4edb893c0 100644 --- a/lib/composio/connectors/buildAuthConfigs.ts +++ b/lib/composio/connectors/buildAuthConfigs.ts @@ -23,5 +23,11 @@ export function buildAuthConfigs(): Record | undefined { if (process.env.COMPOSIO_YOUTUBE_AUTH_CONFIG_ID) { configs.youtube = process.env.COMPOSIO_YOUTUBE_AUTH_CONFIG_ID; } + if (process.env.COMPOSIO_TWITTER_AUTH_CONFIG_ID) { + configs.twitter = process.env.COMPOSIO_TWITTER_AUTH_CONFIG_ID; + } + if (process.env.COMPOSIO_LINKEDIN_AUTH_CONFIG_ID) { + configs.linkedin = process.env.COMPOSIO_LINKEDIN_AUTH_CONFIG_ID; + } return Object.keys(configs).length > 0 ? configs : undefined; } diff --git a/lib/composio/connectors/getConnectors.ts b/lib/composio/connectors/getConnectors.ts index dcb5fb38e..d692bf40c 100644 --- a/lib/composio/connectors/getConnectors.ts +++ b/lib/composio/connectors/getConnectors.ts @@ -23,6 +23,8 @@ const SUPPORTED_TOOLKITS = [ "tiktok", "instagram", "youtube", + "twitter", + "linkedin", ]; /** diff --git a/lib/composio/connectors/getConnectorsHandler.ts b/lib/composio/connectors/getConnectorsHandler.ts index d92f1293d..86633e32b 100644 --- a/lib/composio/connectors/getConnectorsHandler.ts +++ b/lib/composio/connectors/getConnectorsHandler.ts @@ -12,6 +12,8 @@ const CONNECTOR_DISPLAY_NAMES: Record = { googlesheets: "Google Sheets", googledrive: "Google Drive", googledocs: "Google Docs", + twitter: "X (Twitter)", + linkedin: "LinkedIn", }; /** diff --git a/lib/composio/toolRouter/__tests__/getComposioTools.test.ts b/lib/composio/toolRouter/__tests__/getComposioTools.test.ts index f49aff1d1..041521dfb 100644 --- a/lib/composio/toolRouter/__tests__/getComposioTools.test.ts +++ b/lib/composio/toolRouter/__tests__/getComposioTools.test.ts @@ -1,5 +1,12 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { getComposioTools } from "../getComposioTools"; +import { getComposioTools, ENABLED_TOOLKITS } from "../getComposioTools"; + +describe("ENABLED_TOOLKITS", () => { + it("includes twitter and linkedin", () => { + expect(ENABLED_TOOLKITS).toContain("twitter"); + expect(ENABLED_TOOLKITS).toContain("linkedin"); + }); +}); import { getComposioClient } from "../../client"; import { getCallbackUrl } from "../../getCallbackUrl"; diff --git a/lib/composio/toolRouter/getComposioTools.ts b/lib/composio/toolRouter/getComposioTools.ts index 61f0f887f..7f74b4c2f 100644 --- a/lib/composio/toolRouter/getComposioTools.ts +++ b/lib/composio/toolRouter/getComposioTools.ts @@ -16,6 +16,8 @@ export const ENABLED_TOOLKITS = [ "tiktok", "instagram", "youtube", + "twitter", + "linkedin", ]; const SHARED_ACCOUNT_ID = "recoup-shared-767f498e-e1e9-43c6-a152-a96ae3bd8d07"; From 2b34fa63e894c4760f7200ec7458b6b5a0267d9a Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 18 Jun 2026 17:38:07 -0500 Subject: [PATCH 2/2] =?UTF-8?q?chore:=20fix=20lint/format=20=E2=80=94=20re?= =?UTF-8?q?locate=20ENABLED=5FTOOLKITS=20test=20block,=20reformat=20toolki?= =?UTF-8?q?t=20array?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move the ENABLED_TOOLKITS describe block below the imports (import/first) - Prettier-format the expanded toolkits array in getConnectors.test.ts Co-Authored-By: Claude Opus 4.8 (1M context) --- .../connectors/__tests__/getConnectors.test.ts | 18 +++++++++--------- .../__tests__/getComposioTools.test.ts | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/composio/connectors/__tests__/getConnectors.test.ts b/lib/composio/connectors/__tests__/getConnectors.test.ts index cf0f50b06..b637f1026 100644 --- a/lib/composio/connectors/__tests__/getConnectors.test.ts +++ b/lib/composio/connectors/__tests__/getConnectors.test.ts @@ -102,15 +102,15 @@ describe("getConnectors", () => { expect(mockComposio.create).toHaveBeenCalledWith("account-123", { toolkits: [ - "googlesheets", - "googledrive", - "googledocs", - "tiktok", - "instagram", - "youtube", - "twitter", - "linkedin", - ], + "googlesheets", + "googledrive", + "googledocs", + "tiktok", + "instagram", + "youtube", + "twitter", + "linkedin", + ], authConfigs: { tiktok: "ac_tiktok_123", instagram: "ac_instagram_456", diff --git a/lib/composio/toolRouter/__tests__/getComposioTools.test.ts b/lib/composio/toolRouter/__tests__/getComposioTools.test.ts index 041521dfb..ae8d5d718 100644 --- a/lib/composio/toolRouter/__tests__/getComposioTools.test.ts +++ b/lib/composio/toolRouter/__tests__/getComposioTools.test.ts @@ -1,13 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { getComposioTools, ENABLED_TOOLKITS } from "../getComposioTools"; -describe("ENABLED_TOOLKITS", () => { - it("includes twitter and linkedin", () => { - expect(ENABLED_TOOLKITS).toContain("twitter"); - expect(ENABLED_TOOLKITS).toContain("linkedin"); - }); -}); - import { getComposioClient } from "../../client"; import { getCallbackUrl } from "../../getCallbackUrl"; import { getConnectors } from "../../connectors/getConnectors"; @@ -242,3 +235,10 @@ describe("getComposioTools", () => { expect(result).toHaveProperty("COMPOSIO_MULTI_EXECUTE_TOOL"); }); }); + +describe("ENABLED_TOOLKITS", () => { + it("includes twitter and linkedin", () => { + expect(ENABLED_TOOLKITS).toContain("twitter"); + expect(ENABLED_TOOLKITS).toContain("linkedin"); + }); +});