Address PR round 2: use query param, remove inferToolkitSlug, consolidate types

- Rename deprecated `search` param to `query` per Composio docs
- Remove inferToolkitSlug fallback; make toolkit required in ZSearchResultTool
- Replace inline Awaited<ReturnType<...>> with concrete Toolkit type in handler
- Move ZToolkitMeta/ZToolkitItem/ZListToolkitsResponse to shared/composio.ts
- Reference shared schemas in ipc.ts and core/types.ts (single source of truth)
- Remove unused ZTool import from client.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
tusharmagar 2026-04-06 09:58:27 +05:30
parent 5284b10cd4
commit 6c44131794
5 changed files with 41 additions and 63 deletions

View file

@ -4,7 +4,7 @@ import * as composioClient from '@x/core/dist/composio/client.js';
import { composioAccountsRepo } from '@x/core/dist/composio/repo.js';
import { invalidateCopilotInstructionsCache } from '@x/core/dist/application/assistant/instructions.js';
import { CURATED_TOOLKIT_SLUGS } from '@x/shared/dist/composio.js';
import type { LocalConnectedAccount } from '@x/core/dist/composio/types.js';
import type { LocalConnectedAccount, Toolkit } from '@x/core/dist/composio/types.js';
import { triggerSync as triggerGmailSync } from '@x/core/dist/knowledge/sync_gmail.js';
import { triggerSync as triggerCalendarSync } from '@x/core/dist/knowledge/sync_calendar.js';
@ -312,8 +312,7 @@ export async function useComposioForGoogleCalendar(): Promise<{ enabled: boolean
*/
export async function listToolkits() {
// Paginate through all API pages to collect every curated toolkit
type ToolkitItem = Awaited<ReturnType<typeof composioClient.listToolkits>>['items'][number];
const allItems: ToolkitItem[] = [];
const allItems: Toolkit[] = [];
let cursor: string | null = null;
const maxPages = 10; // safety limit
for (let page = 0; page < maxPages; page++) {

View file

@ -15,7 +15,6 @@ import {
ZExecuteActionResponse,
ZListResponse,
ZSearchResultTool,
ZTool,
ZToolkit,
type NormalizedToolResult,
} from "./types.js";
@ -284,21 +283,6 @@ export async function deleteConnectedAccount(connectedAccountId: string): Promis
});
}
/**
* Infer toolkit slug from a tool slug when the API omits the toolkit object.
* Convention: TOOLKIT_ACTION (e.g., GITHUB_CREATE_ISSUE github).
*
* This fallback exists because the Composio /tools search endpoint occasionally
* returns results without the `toolkit` field observed with certain search
* queries and when the tool is from a less-common integration. The inference is
* a best-effort heuristic: lowercase the first segment before the first underscore.
*/
function inferToolkitSlug(toolSlug: string): string {
const lower = toolSlug.toLowerCase();
const parts = lower.split('_');
return parts[0] ?? lower;
}
/**
* Search for tools across all toolkits (or optionally filtered by specific toolkit slugs).
* Returns tools with full input_parameters so the agent knows what params to pass.
@ -311,7 +295,7 @@ export async function searchTools(
toolkitSlugs?: string[],
): Promise<{ items: NormalizedToolResult[] }> {
const params: Record<string, string> = {
search: searchQuery,
query: searchQuery,
limit: '50',
};
if (toolkitSlugs && toolkitSlugs.length === 1) {
@ -324,9 +308,7 @@ export async function searchTools(
slug: item.slug,
name: item.name,
description: item.description,
toolkitSlug: item.toolkit?.slug
|| inferToolkitSlug(item.slug)
|| (toolkitSlugs?.length === 1 ? toolkitSlugs[0] : ''),
toolkitSlug: item.toolkit.slug,
inputParameters: {
type: 'object' as const,
properties: item.input_parameters?.properties ?? {},

View file

@ -1,4 +1,8 @@
import { z } from "zod";
import { ZToolkitMeta as ZSharedToolkitMeta, ZToolkitItem } from "@x/shared/dist/composio.js";
// Re-export the shared toolkit schemas so existing imports continue to work
export const ZToolkitMeta = ZSharedToolkitMeta;
/**
* Composio authentication schemes
@ -29,28 +33,9 @@ export const ZConnectedAccountStatus = z.enum([
]);
/**
* Toolkit metadata
* Toolkit schema same shape as ZToolkitItem from shared, re-exported for convenience.
*/
export const ZToolkitMeta = z.object({
description: z.string(),
logo: z.string(),
tools_count: z.number(),
triggers_count: z.number(),
});
/**
* Toolkit schema
*/
export const ZToolkit = z.object({
slug: z.string(),
name: z.string(),
meta: ZToolkitMeta,
no_auth: z.boolean().optional(),
// Use z.string() instead of ZAuthScheme to be resilient against
// new auth types added by the Composio API over time.
auth_schemes: z.array(z.string()).optional(),
composio_managed_auth_schemes: z.array(z.string()).optional(),
});
export const ZToolkit = ZToolkitItem;
/**
* Tool schema
@ -246,7 +231,7 @@ export const ZSearchResultTool = z.object({
slug: z.string(),
name: z.string(),
logo: z.string(),
}).optional(),
}),
input_parameters: z.object({
type: z.literal('object').optional().default('object'),
properties: z.record(z.string(), z.unknown()).optional().default({}),

View file

@ -1,3 +1,31 @@
import { z } from 'zod';
/**
* Zod schemas for Composio IPC responses.
* Defined here in shared so both ipc.ts and core/composio/types.ts can reference them.
*/
export const ZToolkitMeta = z.object({
description: z.string(),
logo: z.string(),
tools_count: z.number(),
triggers_count: z.number(),
});
export const ZToolkitItem = z.object({
slug: z.string(),
name: z.string(),
meta: ZToolkitMeta,
no_auth: z.boolean().optional(),
auth_schemes: z.array(z.string()).optional(),
composio_managed_auth_schemes: z.array(z.string()).optional(),
});
export const ZListToolkitsResponse = z.object({
items: z.array(ZToolkitItem),
nextCursor: z.string().nullable(),
totalItems: z.number(),
});
/**
* Curated Composio toolkits available to Rowboat users.
* Single source of truth for slugs, display names, and categories.

View file

@ -8,6 +8,7 @@ import { AgentScheduleState } from './agent-schedule-state.js';
import { ServiceEvent } from './service-events.js';
import { UserMessageContent } from './message.js';
import { RowboatApiConfig } from './rowboat-account.js';
import { ZListToolkitsResponse } from './composio.js';
// ============================================================================
// Runtime Validation Schemas (Single Source of Truth)
@ -398,26 +399,9 @@ const ipcSchemas = {
res: z.null(),
},
// Composio Tools Library channels
// Response schema mirrors core/composio/types.ts ZToolkit (kept inline to avoid cross-package import)
'composio:list-toolkits': {
req: z.object({}),
res: z.object({
items: z.array(z.object({
slug: z.string(),
name: z.string(),
meta: z.object({
description: z.string(),
logo: z.string(),
tools_count: z.number(),
triggers_count: z.number(),
}),
no_auth: z.boolean().optional(),
auth_schemes: z.array(z.string()).optional(),
composio_managed_auth_schemes: z.array(z.string()).optional(),
})),
nextCursor: z.string().nullable(),
totalItems: z.number(),
}),
res: ZListToolkitsResponse,
},
// Agent schedule channels
'agent-schedule:getConfig': {