From c0180e2779cd87d2b62cd9a00fe56aeb8a77cc89 Mon Sep 17 00:00:00 2001 From: arkml Date: Wed, 13 Aug 2025 22:45:38 +0530 Subject: [PATCH 1/3] fixed copilot issue with searching composio and applying pipeline tools --- apps/rowboat/app/lib/client_utils.ts | 10 ++++++--- apps/rowboat/app/lib/copilot/copilot.ts | 27 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/apps/rowboat/app/lib/client_utils.ts b/apps/rowboat/app/lib/client_utils.ts index eea2bffb..693a7fed 100644 --- a/apps/rowboat/app/lib/client_utils.ts +++ b/apps/rowboat/app/lib/client_utils.ts @@ -20,10 +20,13 @@ export function validateConfigChanges(configType: string, configChanges: Record< break; } case 'agent': { + // Determine if this is a pipeline agent from the config changes + const isPipelineAgent = configChanges.type === 'pipeline'; + testObject = { name: 'test', description: 'test', - type: 'conversation', + type: isPipelineAgent ? 'pipeline' : 'conversation', instructions: 'test', prompts: [], tools: [], @@ -31,8 +34,9 @@ export function validateConfigChanges(configType: string, configChanges: Record< ragReturnType: 'chunks', ragK: 10, connectedAgents: [], - controlType: 'retain', - outputVisibility: 'user_facing', + // Set correct defaults based on agent type + controlType: isPipelineAgent ? 'relinquish_to_parent' : 'retain', + outputVisibility: isPipelineAgent ? 'internal' : 'user_facing', maxCallsPerParentAgent: 3, } as z.infer; schema = WorkflowAgent; diff --git a/apps/rowboat/app/lib/copilot/copilot.ts b/apps/rowboat/app/lib/copilot/copilot.ts index 2112d9cb..eb26bd3c 100644 --- a/apps/rowboat/app/lib/copilot/copilot.ts +++ b/apps/rowboat/app/lib/copilot/copilot.ts @@ -136,13 +136,38 @@ async function searchRelevantTools(query: string): Promise { return ''; } - const toolSlugs: string[] = searchResult.data.results.map((result: any) => result.tool); + // Log the actual response structure to debug + logger.log("Raw search results:", JSON.stringify(searchResult.data.results, null, 2)); + + // Extract tool slugs with defensive handling for different possible field names + const toolSlugs: string[] = searchResult.data.results + .map((result: any) => { + // Try different possible field names for the tool slug + const slug = result.tool || result.slug || result.tool_slug || result.name; + logger.log(`Processing result:`, { result, extractedSlug: slug }); + return slug; + }) + .filter((slug): slug is string => { + const isValid = typeof slug === 'string' && slug.length > 0; + if (!isValid) { + logger.log(`Filtering out invalid slug:`, slug); + } + return isValid; + }); + logger.log(`found tool slugs: ${toolSlugs.join(', ')}`); console.log("✅ TOOL CALL SUCCESS: COMPOSIO_SEARCH_TOOLS", { toolSlugs, resultCount: toolSlugs.length }); + // Check if we have any valid tool slugs before proceeding + if (toolSlugs.length === 0) { + logger.log("No valid tool slugs found after filtering"); + console.log("⚠️ TOOL CALL WARNING: No valid tools found after filtering"); + return 'No valid tools found for the given query. The search returned results but they contained invalid tool identifiers.'; + } + // Enrich tools with full details console.log("🔧 TOOL CALL: getTool (multiple calls)", { toolSlugs }); const composioTools = await Promise.all(toolSlugs.map(slug => getTool(slug))); From f56ee650cf1b8dbdb59e22617d04cf4b678ddbd4 Mon Sep 17 00:00:00 2001 From: Ramnique Singh <30795890+ramnique@users.noreply.github.com> Date: Thu, 14 Aug 2025 05:37:05 +0530 Subject: [PATCH 2/3] use zod schema for copilot tool search --- apps/rowboat/app/lib/copilot/copilot.ts | 56 +++++++++++-------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/apps/rowboat/app/lib/copilot/copilot.ts b/apps/rowboat/app/lib/copilot/copilot.ts index eb26bd3c..d0276ebf 100644 --- a/apps/rowboat/app/lib/copilot/copilot.ts +++ b/apps/rowboat/app/lib/copilot/copilot.ts @@ -59,6 +59,16 @@ const ZDoneEvent = z.object({ const ZEvent = z.union([ZTextEvent, ZToolCallEvent, ZToolResultEvent, ZDoneEvent]); +const composioToolSearchToolSuggestion = z.object({ + toolkit: z.string(), + tool_slug: z.string(), + description: z.string(), +}); +const composioToolSearchResponseSchema = z.object({ + results: z.array(composioToolSearchToolSuggestion), + related_tools: z.array(composioToolSearchToolSuggestion), +}); + function getContextPrompt(context: z.infer | null): string { let prompt = ''; switch (context?.type) { @@ -127,47 +137,29 @@ async function searchRelevantTools(query: string): Promise { arguments: { use_case: query }, }); - if (!searchResult.successful || !Array.isArray(searchResult.data?.results)) { - logger.log("tool search was not successful or returned no results"); - console.log("❌ TOOL CALL FAILED: COMPOSIO_SEARCH_TOOLS", { - successful: searchResult.successful, - results: searchResult.data?.results - }); - return ''; + if (!searchResult.successful) { + logger.log(`tool search failed: ${searchResult.error}`) + return 'No tools found!'; } - // Log the actual response structure to debug - logger.log("Raw search results:", JSON.stringify(searchResult.data.results, null, 2)); + // parse results + const result = composioToolSearchResponseSchema.safeParse(searchResult.data); + if (!result.success) { + logger.log(`tool search response is invalid: ${result.error}`); + return 'No tools found!'; + } + if (!result.data.results.length) { + logger.log(`tool search yielded no results`); + return 'No tools found!'; + } - // Extract tool slugs with defensive handling for different possible field names - const toolSlugs: string[] = searchResult.data.results - .map((result: any) => { - // Try different possible field names for the tool slug - const slug = result.tool || result.slug || result.tool_slug || result.name; - logger.log(`Processing result:`, { result, extractedSlug: slug }); - return slug; - }) - .filter((slug): slug is string => { - const isValid = typeof slug === 'string' && slug.length > 0; - if (!isValid) { - logger.log(`Filtering out invalid slug:`, slug); - } - return isValid; - }); - + const toolSlugs = result.data.results.map((item) => item.tool_slug); logger.log(`found tool slugs: ${toolSlugs.join(', ')}`); console.log("✅ TOOL CALL SUCCESS: COMPOSIO_SEARCH_TOOLS", { toolSlugs, resultCount: toolSlugs.length }); - // Check if we have any valid tool slugs before proceeding - if (toolSlugs.length === 0) { - logger.log("No valid tool slugs found after filtering"); - console.log("⚠️ TOOL CALL WARNING: No valid tools found after filtering"); - return 'No valid tools found for the given query. The search returned results but they contained invalid tool identifiers.'; - } - // Enrich tools with full details console.log("🔧 TOOL CALL: getTool (multiple calls)", { toolSlugs }); const composioTools = await Promise.all(toolSlugs.map(slug => getTool(slug))); From 402cf40203ea78110743c0744f9ea741155c7198 Mon Sep 17 00:00:00 2001 From: Ramnique Singh <30795890+ramnique@users.noreply.github.com> Date: Thu, 14 Aug 2025 06:04:12 +0530 Subject: [PATCH 3/3] better pipeline agent fix --- apps/rowboat/app/lib/client_utils.ts | 10 +++------- apps/rowboat/app/lib/types/workflow_types.ts | 3 ++- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/rowboat/app/lib/client_utils.ts b/apps/rowboat/app/lib/client_utils.ts index 693a7fed..eea2bffb 100644 --- a/apps/rowboat/app/lib/client_utils.ts +++ b/apps/rowboat/app/lib/client_utils.ts @@ -20,13 +20,10 @@ export function validateConfigChanges(configType: string, configChanges: Record< break; } case 'agent': { - // Determine if this is a pipeline agent from the config changes - const isPipelineAgent = configChanges.type === 'pipeline'; - testObject = { name: 'test', description: 'test', - type: isPipelineAgent ? 'pipeline' : 'conversation', + type: 'conversation', instructions: 'test', prompts: [], tools: [], @@ -34,9 +31,8 @@ export function validateConfigChanges(configType: string, configChanges: Record< ragReturnType: 'chunks', ragK: 10, connectedAgents: [], - // Set correct defaults based on agent type - controlType: isPipelineAgent ? 'relinquish_to_parent' : 'retain', - outputVisibility: isPipelineAgent ? 'internal' : 'user_facing', + controlType: 'retain', + outputVisibility: 'user_facing', maxCallsPerParentAgent: 3, } as z.infer; schema = WorkflowAgent; diff --git a/apps/rowboat/app/lib/types/workflow_types.ts b/apps/rowboat/app/lib/types/workflow_types.ts index edd03a04..4432b426 100644 --- a/apps/rowboat/app/lib/types/workflow_types.ts +++ b/apps/rowboat/app/lib/types/workflow_types.ts @@ -26,7 +26,8 @@ export const WorkflowAgent = z.object({ 'relinquish_to_start', ]).optional().describe('Whether this agent retains control after a turn, relinquishes to the parent agent, or relinquishes to the start agent'), maxCallsPerParentAgent: z.number().default(3).describe('Maximum number of times this agent can be called by a parent agent in a single turn').optional(), -}).refine((data) => { +}); +export const StrictWorkflowAgent = WorkflowAgent.refine((data) => { // Pipeline agents should have internal output visibility and relinquish_to_parent control type if (data.type === 'pipeline' && data.outputVisibility !== 'internal') { return false;