From 0edc89b4a0d4c05d4c3c2784a125d60fcad394c8 Mon Sep 17 00:00:00 2001 From: tusharmagar Date: Thu, 2 Apr 2026 15:47:33 +0530 Subject: [PATCH] Refactor listToolkits function to remove cursor parameter and implement pagination - Updated listToolkits in composio-handler.ts to paginate through API results, collecting all curated toolkits. - Adjusted IPC handler in ipc.ts to call the modified listToolkits without cursor argument. - Made properties in ToolkitInfo optional in settings-dialog.tsx for improved flexibility. - Removed the unused enabled-tools-repo.ts file to clean up the codebase. --- apps/x/apps/main/src/composio-handler.ts | 19 ++- apps/x/apps/main/src/ipc.ts | 4 +- .../src/components/settings-dialog.tsx | 6 +- .../core/src/composio/enabled-tools-repo.ts | 145 ------------------ 4 files changed, 19 insertions(+), 155 deletions(-) delete mode 100644 apps/x/packages/core/src/composio/enabled-tools-repo.ts diff --git a/apps/x/apps/main/src/composio-handler.ts b/apps/x/apps/main/src/composio-handler.ts index c065dd2b..e4986416 100644 --- a/apps/x/apps/main/src/composio-handler.ts +++ b/apps/x/apps/main/src/composio-handler.ts @@ -309,7 +309,7 @@ export async function useComposioForGoogleCalendar(): Promise<{ enabled: boolean /** * List available Composio toolkits — filtered to curated list only */ -export async function listToolkits(cursor?: string): Promise<{ +export async function listToolkits(): Promise<{ items: Array<{ slug: string; name: string; @@ -321,12 +321,21 @@ export async function listToolkits(cursor?: string): Promise<{ nextCursor: string | null; totalItems: number; }> { - // Fetch all toolkits and filter to curated list - const result = await composioClient.listToolkits(cursor || null); - const filtered = result.items.filter(item => CURATED_TOOLKIT_SLUGS.has(item.slug)); + // Paginate through all API pages to collect every curated toolkit + type ToolkitItem = Awaited>['items'][number]; + const allItems: ToolkitItem[] = []; + let cursor: string | null = null; + const maxPages = 10; // safety limit + for (let page = 0; page < maxPages; page++) { + const result = await composioClient.listToolkits(cursor); + allItems.push(...result.items); + cursor = result.next_cursor; + if (!cursor) break; + } + const filtered = allItems.filter(item => CURATED_TOOLKIT_SLUGS.has(item.slug)); return { items: filtered, - nextCursor: result.next_cursor, + nextCursor: null, totalItems: filtered.length, }; } diff --git a/apps/x/apps/main/src/ipc.ts b/apps/x/apps/main/src/ipc.ts index f0fd0b7c..0111ccea 100644 --- a/apps/x/apps/main/src/ipc.ts +++ b/apps/x/apps/main/src/ipc.ts @@ -564,8 +564,8 @@ export function setupIpcHandlers() { return composioHandler.listConnected(); }, // Composio Tools Library handlers - 'composio:list-toolkits': async (_event, args) => { - return composioHandler.listToolkits(args.cursor); + 'composio:list-toolkits': async () => { + return composioHandler.listToolkits(); }, 'composio:use-composio-for-google': async () => { return composioHandler.useComposioForGoogle(); diff --git a/apps/x/apps/renderer/src/components/settings-dialog.tsx b/apps/x/apps/renderer/src/components/settings-dialog.tsx index 9f3ae6fd..66765d14 100644 --- a/apps/x/apps/renderer/src/components/settings-dialog.tsx +++ b/apps/x/apps/renderer/src/components/settings-dialog.tsx @@ -719,9 +719,9 @@ interface ToolkitInfo { slug: string name: string meta: { description: string; logo: string; tools_count: number; triggers_count: number } - no_auth: boolean - auth_schemes: string[] - composio_managed_auth_schemes: string[] + no_auth?: boolean + auth_schemes?: string[] + composio_managed_auth_schemes?: string[] } function ToolsLibrarySettings({ dialogOpen }: { dialogOpen: boolean }) { diff --git a/apps/x/packages/core/src/composio/enabled-tools-repo.ts b/apps/x/packages/core/src/composio/enabled-tools-repo.ts deleted file mode 100644 index 7a2d08e2..00000000 --- a/apps/x/packages/core/src/composio/enabled-tools-repo.ts +++ /dev/null @@ -1,145 +0,0 @@ -import fs from "fs"; -import path from "path"; -import { z } from "zod"; -import { WorkDir } from "../config/config.js"; - -const ENABLED_TOOLS_FILE = path.join(WorkDir, 'data', 'composio', 'enabled_tools.json'); - -/** - * Schema for an enabled Composio tool - */ -export const ZEnabledTool = z.object({ - slug: z.string(), - name: z.string(), - description: z.string(), - toolkitSlug: z.string(), - inputParameters: z.object({ - type: z.literal('object').optional().default('object'), - properties: z.record(z.string(), z.unknown()).optional().default({}), - required: z.array(z.string()).optional(), - }).optional().default({ type: 'object', properties: {} }), -}); - -export type EnabledTool = z.infer; - -/** - * Schema for the enabled tools storage file - */ -const ZEnabledToolsStorage = z.object({ - tools: z.record(z.string(), ZEnabledTool), // keyed by tool slug -}); - -type EnabledToolsStorage = z.infer; - -/** - * Interface for Composio enabled tools repository - */ -export interface IComposioEnabledToolsRepo { - getAll(): Record; - getByToolkit(toolkitSlug: string): EnabledTool[]; - enable(tool: EnabledTool): void; - enableBatch(tools: EnabledTool[]): void; - disable(toolSlug: string): void; - disableBatch(toolSlugs: string[]): void; - disableAllForToolkit(toolkitSlug: string): void; - isEnabled(toolSlug: string): boolean; -} - -function ensureStorageDir(): void { - const dir = path.dirname(ENABLED_TOOLS_FILE); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } -} - -function loadStorageFromDisk(): EnabledToolsStorage { - try { - if (fs.existsSync(ENABLED_TOOLS_FILE)) { - const data = fs.readFileSync(ENABLED_TOOLS_FILE, 'utf-8'); - return ZEnabledToolsStorage.parse(JSON.parse(data)); - } - } catch (error) { - console.error('[ComposioEnabledTools] Failed to load storage:', error); - } - return { tools: {} }; -} - -function saveStorageToDisk(storage: EnabledToolsStorage): void { - ensureStorageDir(); - fs.writeFileSync(ENABLED_TOOLS_FILE, JSON.stringify(storage, null, 2)); -} - -/** - * Repository for managing enabled Composio tools. - * Uses an in-memory cache loaded once from disk. Mutations write through to disk. - */ -export class ComposioEnabledToolsRepo implements IComposioEnabledToolsRepo { - private cache: EnabledToolsStorage | null = null; - - private getStorage(): EnabledToolsStorage { - if (!this.cache) { - this.cache = loadStorageFromDisk(); - } - return this.cache; - } - - private persist(): void { - if (this.cache) { - saveStorageToDisk(this.cache); - } - } - - getAll(): Record { - return this.getStorage().tools; - } - - getByToolkit(toolkitSlug: string): EnabledTool[] { - const storage = this.getStorage(); - return Object.values(storage.tools).filter(t => t.toolkitSlug === toolkitSlug); - } - - enable(tool: EnabledTool): void { - const storage = this.getStorage(); - storage.tools[tool.slug] = tool; - this.persist(); - } - - enableBatch(tools: EnabledTool[]): void { - const storage = this.getStorage(); - for (const tool of tools) { - storage.tools[tool.slug] = tool; - } - this.persist(); - } - - disable(toolSlug: string): void { - const storage = this.getStorage(); - delete storage.tools[toolSlug]; - this.persist(); - } - - disableBatch(toolSlugs: string[]): void { - const storage = this.getStorage(); - for (const slug of toolSlugs) { - delete storage.tools[slug]; - } - this.persist(); - } - - disableAllForToolkit(toolkitSlug: string): void { - const storage = this.getStorage(); - for (const [slug, tool] of Object.entries(storage.tools)) { - if (tool.toolkitSlug === toolkitSlug) { - delete storage.tools[slug]; - } - } - this.persist(); - } - - isEnabled(toolSlug: string): boolean { - const storage = this.getStorage(); - return toolSlug in storage.tools; - } -} - -export const composioEnabledToolsRepo = new ComposioEnabledToolsRepo();