mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-03 19:25:19 +02:00
attach composio search feature to copilot llm call itself
This commit is contained in:
parent
3fbc739a24
commit
f17bc37583
1 changed files with 30 additions and 50 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import z from "zod";
|
||||
import { createOpenAI } from "@ai-sdk/openai";
|
||||
import { generateObject, generateText, streamText } from "ai";
|
||||
import { generateObject, streamText, tool } from "ai";
|
||||
import { WithStringId } from "../types/types";
|
||||
import { Workflow, WorkflowTool } from "../types/workflow_types";
|
||||
import { CopilotChatContext, CopilotMessage } from "../types/copilot_types";
|
||||
|
|
@ -96,54 +96,31 @@ ${JSON.stringify(simplifiedDataSources)}
|
|||
return prompt;
|
||||
}
|
||||
|
||||
async function getDynamicToolsPrompt(messages: z.infer<typeof CopilotMessage>[], workflow: z.infer<typeof Workflow>): Promise<string> {
|
||||
console.log('--- [Co-pilot] Entering Dynamic Tool Creation ---');
|
||||
async function searchRelevantTools(query: string): Promise<string> {
|
||||
const logger = new PrefixLogger("copilot-search-tools");
|
||||
if (!USE_COMPOSIO_TOOLS) {
|
||||
console.log('[Co-pilot] Dynamic tool creation is disabled.');
|
||||
return '';
|
||||
}
|
||||
|
||||
// first, check if we need to search for tools at all
|
||||
const startTime = Date.now();
|
||||
const { text } = await generateText({
|
||||
model: openai(COPILOT_MODEL),
|
||||
system: `Your task is to determine if a tool search is required based on the user's request. Respond with a single word: 'yes' or 'no'.
|
||||
|
||||
Say 'yes' if:
|
||||
- The user explicitly mentions a tool or a capability that requires a tool (e.g., "send an email", "connect to an API").
|
||||
- The user describes a goal or workflow that implies the need for external actions or data (e.g., "build an agent to manage my files").
|
||||
- The user asks for a tool to be added to the workflow.
|
||||
- The user asks questions bout how to perform a task.
|
||||
|
||||
Otherwise, say 'no'. Also important to remember if a tool has already been searched and is in context there is no need to search again.`,
|
||||
messages,
|
||||
});
|
||||
console.log("[Co-pilot] Sending the following messages to the LLM for tool search check:", JSON.stringify(messages, null, 2));
|
||||
const endTime = Date.now();
|
||||
console.log(`[Co-pilot] Tool search check took ${endTime - startTime}ms`);
|
||||
console.log("[Co-pilot] LLM response:", text);
|
||||
if (text.toLowerCase() !== "yes") {
|
||||
console.log('[Co-pilot] No tool search needed.');
|
||||
return '';
|
||||
logger.log("dynamic tool search is disabled");
|
||||
return 'No tools found!';
|
||||
}
|
||||
|
||||
const composio = new Composio();
|
||||
|
||||
// Step 1: Search for relevant tool slugs
|
||||
console.log('[Co-pilot] 🚀 Searching for relevant tools...');
|
||||
// Search for relevant tool slugs
|
||||
logger.log('searching for relevant tools...');
|
||||
const searchResult = await composio.tools.execute('COMPOSIO_SEARCH_TOOLS', {
|
||||
userId: '0000-0000-0000', // hmmmmm
|
||||
arguments: { use_case: messages[messages.length - 1].content }, // use last message
|
||||
userId: '0000-0000-0000',
|
||||
arguments: { use_case: query },
|
||||
});
|
||||
|
||||
if (!searchResult.successful || !Array.isArray(searchResult.data?.results)) {
|
||||
console.warn('[Co-pilot] ⚠️ Tool search was not successful or returned no results.');
|
||||
logger.log("tool search was not successful or returned no results");
|
||||
return '';
|
||||
}
|
||||
|
||||
const toolSlugs: string[] = searchResult.data.results.map((result: any) => result.tool);
|
||||
console.log(`[Co-pilot] ✅ Found tool slugs: ${toolSlugs.join(', ')}`);
|
||||
logger.log(`found tool slugs: ${toolSlugs.join(', ')}`);
|
||||
|
||||
// Enrich tools with full details
|
||||
const composioTools = await Promise.all(toolSlugs.map(slug => getTool(slug)));
|
||||
const workflowTools: z.infer<typeof WorkflowTool>[] = composioTools.map(tool => ({
|
||||
name: tool.name,
|
||||
|
|
@ -163,19 +140,14 @@ Otherwise, say 'no'. Also important to remember if a tool has already been searc
|
|||
},
|
||||
}));
|
||||
|
||||
console.log('--- [Co-pilot] Exiting Dynamic Tool Creation (Success) ---');
|
||||
// Format the response
|
||||
const toolConfigs = workflowTools.map(tool =>
|
||||
`**${tool.name}**:\n\`\`\`json\n${JSON.stringify(tool, null, 2)}\n\`\`\``
|
||||
).join('\n\n');
|
||||
|
||||
const prompt = `## Tool Suggestions:
|
||||
The following are tools suggestions being made by the AI. These are composio tools and they must be added first to the workflow before they can be used.
|
||||
|
||||
${toolConfigs}
|
||||
|
||||
To add any tool you can copy the above json as an add tool block`;
|
||||
console.log(prompt);
|
||||
return prompt;
|
||||
const response = `The following tools were found:\n\n${toolConfigs}`;
|
||||
logger.log('returning response', response);
|
||||
return response;
|
||||
}
|
||||
|
||||
function updateLastUserMessage(
|
||||
|
|
@ -183,11 +155,10 @@ function updateLastUserMessage(
|
|||
currentWorkflowPrompt: string,
|
||||
contextPrompt: string,
|
||||
dataSourcesPrompt: string = '',
|
||||
dynamicToolsPrompt: string = '',
|
||||
): void {
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
if (lastMessage.role === 'user') {
|
||||
lastMessage.content = `${currentWorkflowPrompt}\n\n${contextPrompt}\n\n${dataSourcesPrompt}\n\n${dynamicToolsPrompt}\n\nUser: ${JSON.stringify(lastMessage.content)}`;
|
||||
lastMessage.content = `${currentWorkflowPrompt}\n\n${contextPrompt}\n\n${dataSourcesPrompt}\n\nUser: ${JSON.stringify(lastMessage.content)}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,11 +224,8 @@ export async function* streamMultiAgentResponse(
|
|||
// set data sources prompt
|
||||
let dataSourcesPrompt = getDataSourcesPrompt(dataSources);
|
||||
|
||||
// get dynamic tools prompt
|
||||
const dynamicToolsPrompt = await getDynamicToolsPrompt(messages, workflow);
|
||||
|
||||
// add the above prompts to the last user message
|
||||
updateLastUserMessage(messages, currentWorkflowPrompt, contextPrompt, dataSourcesPrompt, dynamicToolsPrompt);
|
||||
updateLastUserMessage(messages, currentWorkflowPrompt, contextPrompt, dataSourcesPrompt);
|
||||
|
||||
// call model
|
||||
console.log("calling model", JSON.stringify({
|
||||
|
|
@ -267,6 +235,18 @@ export async function* streamMultiAgentResponse(
|
|||
}));
|
||||
const { textStream } = streamText({
|
||||
model: openai(COPILOT_MODEL),
|
||||
maxSteps: 5,
|
||||
tools: {
|
||||
"search_relevant_tools": tool({
|
||||
description: "Search for relevant tools",
|
||||
parameters: z.object({
|
||||
query: z.string().describe("the use-case to search for"),
|
||||
}),
|
||||
execute: async ({ query }: { query: string }) => {
|
||||
return await searchRelevantTools(query);
|
||||
},
|
||||
}),
|
||||
},
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue