fix composio API integration: URL construction, schema validation, and executeAction calls

- Fix URL construction in composioApiCall to preserve base path (/api/v3)
- Make ZToolkit and ZTool schema fields optional to match actual API responses
- Fix error detection to not trigger on successful responses with null error
- Fix executeAction calls in sync_gmail to use correct request object shape
- Use .successful instead of .success to match ZExecuteActionResponse schema

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arjun 2026-03-16 09:57:55 +05:30
parent 17bb625ab9
commit dd361cb6bf
4 changed files with 21 additions and 13 deletions

View file

@ -70,7 +70,7 @@ export async function initiateConnection(toolkitSlug: string): Promise<{
const toolkit = await composioClient.getToolkit(toolkitSlug);
// Check for managed OAuth2
if (!toolkit.composio_managed_auth_schemes.includes('OAUTH2')) {
if (!toolkit.composio_managed_auth_schemes?.includes('OAUTH2')) {
return {
success: false,
error: `Toolkit ${toolkitSlug} does not support managed OAuth2`,

View file

@ -123,7 +123,7 @@ export async function composioApiCall<T extends z.ZodTypeAny>(
): Promise<z.infer<T>> {
const authHeaders = await getAuthHeaders();
const baseURL = await getBaseUrl();
const url = new URL(path, baseURL);
const url = new URL(`${baseURL}${path}`);
console.log(`[Composio] ${options.method || 'GET'} ${url}`);
const startTime = Date.now();
@ -171,7 +171,7 @@ export async function composioApiCall<T extends z.ZodTypeAny>(
throw new Error(`Failed to parse response: ${message}`);
}
if (typeof data === 'object' && data !== null && 'error' in data) {
if (typeof data === 'object' && data !== null && 'error' in data && data.error !== null && typeof data.error === 'object') {
const parsedError = ZErrorResponse.parse(data);
throw new Error(`Composio error (${parsedError.error.error_code}): ${parsedError.error.message}`);
}

View file

@ -45,9 +45,9 @@ export const ZToolkit = z.object({
slug: z.string(),
name: z.string(),
meta: ZToolkitMeta,
no_auth: z.boolean(),
auth_schemes: z.array(ZAuthScheme),
composio_managed_auth_schemes: z.array(ZAuthScheme),
no_auth: z.boolean().optional(),
auth_schemes: z.array(ZAuthScheme).optional(),
composio_managed_auth_schemes: z.array(ZAuthScheme).optional(),
});
/**
@ -68,7 +68,7 @@ export const ZTool = z.object({
required: z.array(z.string()).optional(),
additionalProperties: z.boolean().optional(),
}),
no_auth: z.boolean(),
no_auth: z.boolean().optional(),
});
/**

View file

@ -562,15 +562,19 @@ async function processThreadComposio(connectedAccountId: string, threadId: strin
try {
threadResult = await executeAction(
'GMAIL_FETCH_MESSAGE_BY_THREAD_ID',
connectedAccountId,
{ thread_id: threadId, user_id: 'me' }
{
connected_account_id: connectedAccountId,
user_id: 'rowboat-user',
version: 'latest',
arguments: { thread_id: threadId, user_id: 'me' },
}
);
} catch (error) {
console.warn(`[Gmail] Skipping thread ${threadId} (fetch failed):`, error instanceof Error ? error.message : error);
return null;
}
if (!threadResult.success || !threadResult.data) {
if (!threadResult.successful || !threadResult.data) {
console.error(`[Gmail] Failed to fetch thread ${threadId}:`, threadResult.error);
return null;
}
@ -674,11 +678,15 @@ async function performSyncComposio() {
const result = await executeAction(
'GMAIL_LIST_THREADS',
connectedAccountId,
params
{
connected_account_id: connectedAccountId,
user_id: 'rowboat-user',
version: 'latest',
arguments: params,
}
);
if (!result.success || !result.data) {
if (!result.successful || !result.data) {
console.error('[Gmail] Failed to list threads:', result.error);
return;
}