From 01b537ade16d797a5564dce6449480f862f90c4b Mon Sep 17 00:00:00 2001 From: ItzCrazyKns <95534749+ItzCrazyKns@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:41:55 +0530 Subject: [PATCH] feat(actions): add tool description, description --- .../agents/search/researcher/actions/done.ts | 13 +++- .../agents/search/researcher/actions/plan.ts | 17 ++++- .../search/researcher/actions/registry.ts | 8 ++- .../search/researcher/actions/scrapeURL.ts | 12 +++- .../search/researcher/actions/webSearch.ts | 70 ++++++++++++++++--- src/lib/agents/search/researcher/index.ts | 3 + 6 files changed, 105 insertions(+), 18 deletions(-) diff --git a/src/lib/agents/search/researcher/actions/done.ts b/src/lib/agents/search/researcher/actions/done.ts index bfed3e2..b19df4f 100644 --- a/src/lib/agents/search/researcher/actions/done.ts +++ b/src/lib/agents/search/researcher/actions/done.ts @@ -1,12 +1,19 @@ import z from 'zod'; import { ResearchAction } from '../../types'; +const actionDescription = ` +Use this action ONLY when you have completed all necessary research and are ready to provide a final answer to the user. This indicates that you have gathered sufficient information from previous steps and are concluding the research process. +YOU MUST CALL THIS ACTION TO SIGNAL COMPLETION; DO NOT OUTPUT FINAL ANSWERS DIRECTLY TO THE USER. +IT WILL BE AUTOMATICALLY TRIGGERED IF MAXIMUM ITERATIONS ARE REACHED SO IF YOU'RE LOW ON ITERATIONS, DON'T CALL IT AND INSTEAD FOCUS ON GATHERING ESSENTIAL INFO FIRST. +` + const doneAction: ResearchAction = { name: 'done', - description: - 'Only call this after ___plan AND after any other needed tool calls when you truly have enough to answer. Do not call if information is still missing.', - enabled: (_) => true, schema: z.object({}), + getToolDescription: () => + 'Only call this after ___plan AND after any other needed tool calls when you truly have enough to answer. Do not call if information is still missing.', + getDescription: () => actionDescription, + enabled: (_) => true, execute: async (params, additionalConfig) => { return { type: 'done', diff --git a/src/lib/agents/search/researcher/actions/plan.ts b/src/lib/agents/search/researcher/actions/plan.ts index d4d7661..dcdd05b 100644 --- a/src/lib/agents/search/researcher/actions/plan.ts +++ b/src/lib/agents/search/researcher/actions/plan.ts @@ -9,12 +9,23 @@ const schema = z.object({ ), }); +const actionDescription = ` +Use thi tool FIRST on every turn to state your plan in natural language before any other action. Keep it short, action-focused, and tailored to the current query. +Make sure to not include reference to any tools or actions you might take, just the plan itself. The user isn't aware about tools, but they love to see your thought process. + +Here are some examples of good plans: + +- "Okay, the user wants to know the latest advancements in renewable energy. I will start by looking for recent articles and studies on this topic, then summarize the key points." -> "I have gathered enough information to provide a comprehensive answer." +- "The user is asking about the health benefits of a Mediterranean diet. I will search for scientific studies and expert opinions on this diet, then compile the findings into a clear summary." -> "I have gathered information about the Mediterranean diet and its health benefits, I will now look up for any recent studies to ensure the information is current." + +` + const planAction: ResearchAction = { name: '___plan', - description: - 'Use this FIRST on every turn to state your plan in natural language before any other action. Keep it short, action-focused, and tailored to the current query.', schema: schema, - enabled: (_) => true, + getToolDescription: () => 'Use this FIRST on every turn to state your plan in natural language before any other action. Keep it short, action-focused, and tailored to the current query.', + getDescription: () => actionDescription, + enabled: (config) => config.mode !== 'speed', execute: async (input, _) => { return { type: 'reasoning', diff --git a/src/lib/agents/search/researcher/actions/registry.ts b/src/lib/agents/search/researcher/actions/registry.ts index 7454763..3a8eda6 100644 --- a/src/lib/agents/search/researcher/actions/registry.ts +++ b/src/lib/agents/search/researcher/actions/registry.ts @@ -4,6 +4,7 @@ import { AdditionalConfig, ClassifierOutput, ResearchAction, + SearchAgentConfig, } from '../../types'; class ActionRegistry { @@ -19,6 +20,7 @@ class ActionRegistry { static getAvailableActions(config: { classification: ClassifierOutput; + mode: SearchAgentConfig['mode']; }): ResearchAction[] { return Array.from( this.actions.values().filter((action) => action.enabled(config)), @@ -27,23 +29,25 @@ class ActionRegistry { static getAvailableActionTools(config: { classification: ClassifierOutput; + mode: SearchAgentConfig['mode']; }): Tool[] { const availableActions = this.getAvailableActions(config); return availableActions.map((action) => ({ name: action.name, - description: action.description, + description: action.getToolDescription({ mode: config.mode }), schema: action.schema, })); } static getAvailableActionsDescriptions(config: { classification: ClassifierOutput; + mode: SearchAgentConfig['mode']; }): string { const availableActions = this.getAvailableActions(config); return availableActions - .map((action) => `------------\n##${action.name}\n${action.description}`) + .map((action) => `\n${action.getDescription({ mode: config.mode })}\n`) .join('\n\n'); } diff --git a/src/lib/agents/search/researcher/actions/scrapeURL.ts b/src/lib/agents/search/researcher/actions/scrapeURL.ts index 03dea2f..3d3173e 100644 --- a/src/lib/agents/search/researcher/actions/scrapeURL.ts +++ b/src/lib/agents/search/researcher/actions/scrapeURL.ts @@ -10,11 +10,19 @@ const schema = z.object({ urls: z.array(z.string()).describe('A list of URLs to scrape content from.'), }); +const actionDescription = ` +Use this tool to scrape and extract content from the provided URLs. This is useful when you the user has asked you to extract or summarize information from specific web pages. You can provide up to 3 URLs at a time. NEVER CALL THIS TOOL EXPLICITLY YOURSELF UNLESS INSTRUCTED TO DO SO BY THE USER. +You should only call this tool when the user has specifically requested information from certain web pages, never call this yourself to get extra information without user instruction. + +For example, if the user says "Please summarize the content of https://example.com/article", you can call this tool with that URL to get the content and then provide the summary or "What does X mean according to https://example.com/page", you can call this tool with that URL to get the content and provide the explanation. +` + const scrapeURLAction: ResearchAction = { name: 'scrape_url', - description: - 'Use this tool to scrape and extract content from the provided URLs. This is useful when you the user has asked you to extract or summarize information from specific web pages. You can provide up to 3 URLs at a time. NEVER CALL THIS TOOL EXPLICITLY YOURSELF UNLESS INSTRUCTED TO DO SO BY THE USER.', schema: schema, + getToolDescription: () => + 'Use this tool to scrape and extract content from the provided URLs. This is useful when you the user has asked you to extract or summarize information from specific web pages. You can provide up to 3 URLs at a time. NEVER CALL THIS TOOL EXPLICITLY YOURSELF UNLESS INSTRUCTED TO DO SO BY THE USER.', + getDescription: () => actionDescription, enabled: (_) => true, execute: async (params, additionalConfig) => { params.urls = params.urls.slice(0, 3); diff --git a/src/lib/agents/search/researcher/actions/webSearch.ts b/src/lib/agents/search/researcher/actions/webSearch.ts index f148155..04e9702 100644 --- a/src/lib/agents/search/researcher/actions/webSearch.ts +++ b/src/lib/agents/search/researcher/actions/webSearch.ts @@ -10,22 +10,76 @@ const actionSchema = z.object({ .describe('An array of search queries to perform web searches for.'), }); -const actionDescription = ` -Use immediately after the ___plan call when you need information. Default to using this unless you already have everything needed to finish. Provide 1-3 short, SEO-friendly queries (keywords, not sentences) that cover the user ask. Always prefer current/contextual queries (e.g., include year for news). +const speedModePrompt = ` +Use this tool to perform web searches based on the provided queries. This is useful when you need to gather information from the web to answer the user's questions. You can provide up to 3 queries at a time. You will have to use this every single time if this is present and relevant. +You are currently on speed mode, meaning you would only get to call this tool once. Make sure to prioritize the most important queries that are likely to get you the needed information in one go. -You can search maximum of 3 queries at a time. +Your queries should be very targeted and specific to the information you need, avoid broad or generic queries. +Your queries shouldn't be sentences but rather keywords that are SEO friendly and can be used to search the web for information. -For fast mode, you can only use this tool once so make sure to get all needed information in one go. +For example, if the user is asking about the features of a new technology, you might use queries like "GPT-5.1 features", "GPT-5.1 release date", "GPT-5.1 improvements" rather than a broad query like "Tell me about GPT-5.1". -For balanced and quality modes, you can use this tool multiple times as needed. +You can search for 3 queries in one go, make sure to utilize all 3 queries to maximize the information you can gather. If a question is simple, then split your queries to cover different aspects or related topics to get a comprehensive understanding. +If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed information. +` -In quality and balanced mode, first try to gather upper level information with broad queries, then use more specific queries based on what you find to find all information needed. -`; +const balancedModePrompt = ` +Use this tool to perform web searches based on the provided queries. This is useful when you need to gather information from the web to answer the user's questions. You can provide up to 3 queries at a time. You will have to use this every single time if this is present and relevant. + +You can call this tool several times if needed to gather enough information. +Start initially with broader queries to get an overview, then narrow down with more specific queries based on the results you receive. + +Your queries shouldn't be sentences but rather keywords that are SEO friendly and can be used to search the web for information. + +For example if the user is asking about Tesla, your actions should be like: +1. __plan "The user is asking about Tesla. I will start with broader queries to get an overview of Tesla, then narrow down with more specific queries based on the results I receive." then +2. web_search ["Tesla", "Tesla latest news", "Tesla stock price"] then +3. __plan "Based on the previous search results, I will now narrow down my queries to focus on Tesla's recent developments and stock performance." then +4. web_search ["Tesla Q2 2025 earnings", "Tesla new model 2025", "Tesla stock analysis"] then done. +5. __plan "I have gathered enough information to provide a comprehensive answer." +6. done. + +You can search for 3 queries in one go, make sure to utilize all 3 queries to maximize the information you can gather. If a question is simple, then split your queries to cover different aspects or related topics to get a comprehensive understanding. +If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed information. You can call this tools, multiple times as needed. +` + +const qualityModePrompt = ` +Use this tool to perform web searches based on the provided queries. This is useful when you need to gather information from the web to answer the user's questions. You can provide up to 3 queries at a time. You will have to use this every single time if this is present and relevant. + +You have to call this tool several times to gather enough information unless the question is very simple (like greeting questions or basic facts). +Start initially with broader queries to get an overview, then narrow down with more specific queries based on the results you receive. +Never stop before at least 5-6 iterations of searches unless the user question is very simple. + +Your queries shouldn't be sentences but rather keywords that are SEO friendly and can be used to search the web for information. + +You can search for 3 queries in one go, make sure to utilize all 3 queries to maximize the information you can gather. If a question is simple, then split your queries to cover different aspects or related topics to get a comprehensive understanding. +If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed information. You can call this tools, multiple times as needed. +` const webSearchAction: ResearchAction = { name: 'web_search', - description: actionDescription, schema: actionSchema, + getToolDescription: () => 'Use this tool to perform web searches based on the provided queries. This is useful when you need to gather information from the web to answer the user\'s questions. You can provide up to 3 queries at a time. You will have to use this every single time if this is present and relevant.', + getDescription: (config) => { + let prompt = '' + + switch (config.mode) { + case 'speed': + prompt = speedModePrompt + break; + case 'balanced': + prompt = balancedModePrompt + break; + case 'quality': + prompt = qualityModePrompt + break; + default: + prompt = speedModePrompt + break; + } + + return prompt + }, enabled: (config) => config.classification.classification.skipSearch === false, execute: async (input, additionalConfig) => { diff --git a/src/lib/agents/search/researcher/index.ts b/src/lib/agents/search/researcher/index.ts index feb450f..6762a61 100644 --- a/src/lib/agents/search/researcher/index.ts +++ b/src/lib/agents/search/researcher/index.ts @@ -5,6 +5,7 @@ import SessionManager from '@/lib/session'; import { Message, ReasoningResearchBlock } from '@/lib/types'; import formatChatHistoryAsString from '@/lib/utils/formatHistory'; import { ToolCall } from '@/lib/models/types'; +import fs from 'fs'; class Researcher { async research( @@ -21,11 +22,13 @@ class Researcher { const availableTools = ActionRegistry.getAvailableActionTools({ classification: input.classification, + mode: input.config.mode, }); const availableActionsDescription = ActionRegistry.getAvailableActionsDescriptions({ classification: input.classification, + mode: input.config.mode }); const researchBlockId = crypto.randomUUID();