feat(classifier): switch to a fixed approach

This commit is contained in:
ItzCrazyKns
2025-12-01 18:33:54 +05:30
parent 610d06be36
commit 9b3833f933
12 changed files with 108 additions and 601 deletions

View File

@@ -0,0 +1,50 @@
import z from 'zod';
import { ClassifierInput } from './types';
import { classifierPrompt } from '@/lib/prompts/search/classifier';
import formatChatHistoryAsString from '@/lib/utils/formatHistory';
const schema = z.object({
classification: z.object({
skipSearch: z
.boolean()
.describe('Indicates whether to skip the search step.'),
personalSearch: z
.boolean()
.describe('Indicates whether to perform a personal search.'),
academicSearch: z
.boolean()
.describe('Indicates whether to perform an academic search.'),
discussionSearch: z
.boolean()
.describe('Indicates whether to perform a discussion search.'),
showWeatherWidget: z
.boolean()
.describe('Indicates whether to show the weather widget.'),
showStockWidget: z
.boolean()
.describe('Indicates whether to show the stock widget.'),
}),
standaloneFollowUp: z
.string()
.describe(
"A self-contained, context-independent reformulation of the user's question.",
),
});
export const classify = async (input: ClassifierInput) => {
const output = await input.llm.generateObject<typeof schema>({
messages: [
{
role: 'system',
content: classifierPrompt,
},
{
role: 'user',
content: `<conversation_history>\n${formatChatHistoryAsString(input.chatHistory)}\n</conversation_history>\n<user_query>\n${input.query}\n</user_query>`,
},
],
schema,
});
return output;
};

View File

@@ -1,73 +0,0 @@
import z from 'zod';
import { ClassifierInput, ClassifierOutput } from '../types';
import { WidgetRegistry } from '../widgets';
import { IntentRegistry } from './intents';
import { getClassifierPrompt } from '@/lib/prompts/search/classifier';
import formatChatHistoryAsString from '@/lib/utils/formatHistory';
class Classifier {
async classify(input: ClassifierInput): Promise<ClassifierOutput> {
const availableIntents = IntentRegistry.getAvailableIntents({
sources: input.enabledSources,
});
const availableWidgets = WidgetRegistry.getAll();
const classificationSchema = z.object({
skipSearch: z
.boolean()
.describe(
'Set to true to SKIP search. Skip ONLY when: (1) widgets alone fully answer the query (e.g., weather, stocks, calculator), (2) simple greetings or writing tasks (NOT questions). Set to false for ANY question or information request.',
),
standaloneFollowUp: z
.string()
.describe(
"A self-contained, context-independent reformulation of the user's question. Must include all necessary context from chat history, replace pronouns with specific nouns, and be clear enough to answer without seeing the conversation. Keep the same complexity as the original question.",
),
intents: z
.array(z.enum(availableIntents.map((i) => i.name)))
.describe(
"The intent(s) that best describe how to fulfill the user's query. Can include multiple intents (e.g., ['web_search', 'widget_response'] for 'weather in NYC and recent news'). Always include at least one intent when applicable.",
),
widgets: z
.array(z.union(availableWidgets.map((w) => w.schema)))
.describe(
'Widgets that can display structured data to answer (fully or partially) the query. Include all applicable widgets regardless of skipSearch value.',
),
});
const classifierPrompt = getClassifierPrompt({
intentDesc: IntentRegistry.getDescriptions({
sources: input.enabledSources,
}),
widgetDesc: WidgetRegistry.getDescriptions(),
});
const res = await input.llm.generateObject<
z.infer<typeof classificationSchema>
>({
messages: [
{
role: 'system',
content: classifierPrompt,
},
{
role: 'user',
content: `<conversation>${formatChatHistoryAsString(input.chatHistory)}</conversation>\n\n<query>${input.query}</query>`,
},
],
schema: classificationSchema,
});
res.widgets = res.widgets.map((widgetConfig) => {
return {
type: widgetConfig.type,
params: widgetConfig,
};
});
return res as ClassifierOutput;
}
}
export default Classifier;

View File

@@ -1,52 +0,0 @@
import { Intent } from '../../types';
const description = `Use this intent to search for scholarly articles, research papers, scientific studies, and academic resources when the user explicitly requests credible, peer-reviewed, or authoritative information from academic sources.
#### When to use:
1. User explicitly mentions academic keywords: research papers, scientific studies, scholarly articles, peer-reviewed, journal articles.
2. User asks for scientific evidence or academic research on a topic.
3. User needs authoritative, citation-worthy sources for research or academic purposes.
#### When NOT to use:
1. General questions that don't specifically request academic sources - use 'web_search' instead.
2. User just wants general information without specifying academic sources.
3. Casual queries about facts or current events.
#### Example use cases:
1. "Find scientific papers on climate change effects"
- User explicitly wants scientific papers.
- Intent: ['academic_search'] with skipSearch: false
2. "What does the research say about meditation benefits?"
- User is asking for research-based information.
- Intent: ['academic_search', 'web_search'] with skipSearch: false
3. "Show me peer-reviewed articles on CRISPR technology"
- User specifically wants peer-reviewed academic content.
- Intent: ['academic_search'] with skipSearch: false
4. "I need scholarly sources about renewable energy for my thesis"
- User explicitly needs scholarly/academic sources.
- Intent: ['academic_search'] with skipSearch: false
5. "Explain quantum computing" (WRONG to use academic_search alone)
- This is a general question, not specifically requesting academic papers.
- Correct intent: ['web_search'] with skipSearch: false
- Could combine: ['web_search', 'academic_search'] if you want both general and academic sources
6. "What's the latest study on sleep patterns?"
- User mentions "study" - combine academic and web search for comprehensive results.
- Intent: ['academic_search', 'web_search'] with skipSearch: false
**IMPORTANT**: This intent can be combined with 'web_search' to provide both academic papers and general web information. Always set skipSearch to false when using this intent.
**NOTE**: This intent is only available if academic search sources are enabled in the configuration.`;
const academicSearchIntent: Intent = {
name: 'academic_search',
description,
requiresSearch: true,
enabled: (config) => config.sources.includes('academic'),
};
export default academicSearchIntent;

View File

@@ -1,55 +0,0 @@
import { Intent } from '../../types';
const description = `Use this intent to search through discussion forums, community boards, and social platforms (Reddit, forums, etc.) when the user explicitly wants opinions, personal experiences, community discussions, or crowd-sourced information.
#### When to use:
1. User explicitly mentions: Reddit, forums, discussion boards, community opinions, "what do people think", "user experiences".
2. User is asking for opinions, reviews, or personal experiences about a product, service, or topic.
3. User wants to know what communities or people are saying about something.
#### When NOT to use:
1. General questions that don't specifically ask for opinions or discussions - use 'web_search' instead.
2. User wants factual information or official sources.
3. Casual queries about facts, news, or current events without requesting community input.
#### Example use cases:
1. "What do people on Reddit think about the new iPhone?"
- User explicitly wants Reddit/community opinions.
- Intent: ['discussions_search'] with skipSearch: false
2. "User experiences with Tesla Model 3"
- User is asking for personal experiences from users.
- Intent: ['discussions_search'] with skipSearch: false
3. "Best gaming laptop according to forums"
- User wants forum/community recommendations.
- Intent: ['discussions_search'] with skipSearch: false
4. "What are people saying about the new AI regulations?"
- User wants community discussions/opinions.
- Intent: ['discussions_search', 'web_search'] with skipSearch: false
5. "Reviews and user opinions on the Framework laptop"
- Combines user opinions with general reviews.
- Intent: ['discussions_search', 'web_search'] with skipSearch: false
6. "What's the price of iPhone 15?" (WRONG to use discussions_search)
- This is a factual question, not asking for opinions.
- Correct intent: ['web_search'] with skipSearch: false
7. "Explain how OAuth works" (WRONG to use discussions_search)
- This is asking for information, not community opinions.
- Correct intent: ['web_search'] with skipSearch: false
**IMPORTANT**: This intent can be combined with 'web_search' to provide both community discussions and official/factual information. Always set skipSearch to false when using this intent.
**NOTE**: This intent is only available if discussion search sources are enabled in the configuration.`;
const discussionSearchIntent: Intent = {
name: 'discussions_search',
description,
requiresSearch: true,
enabled: (config) => config.sources.includes('discussions'),
};
export default discussionSearchIntent;

View File

@@ -1,16 +0,0 @@
import academicSearchIntent from './academicSearch';
import discussionSearchIntent from './discussionSearch';
import privateSearchIntent from './privateSearch';
import IntentRegistry from './registry';
import webSearchIntent from './webSearch';
import widgetResponseIntent from './widgetResponse';
import writingTaskIntent from './writingTask';
IntentRegistry.register(webSearchIntent);
IntentRegistry.register(academicSearchIntent);
IntentRegistry.register(discussionSearchIntent);
IntentRegistry.register(widgetResponseIntent);
IntentRegistry.register(writingTaskIntent);
IntentRegistry.register(privateSearchIntent);
export { IntentRegistry };

View File

@@ -1,47 +0,0 @@
import { Intent } from '../../types';
const description = `Use this intent to search through the user's uploaded documents or provided web page links when they ask questions about their personal files or specific URLs.
#### When to use:
1. User explicitly asks about uploaded documents ("tell me about the document I uploaded", "summarize this file").
2. User provides specific URLs/links and asks questions about them ("tell me about example.com", "what's on this page: url.com").
3. User references "my documents", "the file I shared", "this link" when files or URLs are available.
#### When NOT to use:
1. User asks generic questions like "summarize" without providing context or files (later the system will ask what they want summarized).
2. No files have been uploaded and no URLs provided - use web_search or other intents instead.
3. User is asking general questions unrelated to their uploaded content.
#### Example use cases:
1. "Tell me about the PDF I uploaded"
- Files are uploaded, user wants information from them.
- Intent: ['private_search'] with skipSearch: false
2. "What's the main point from example.com?"
- User provided a specific URL to analyze.
- Intent: ['private_search'] with skipSearch: false
3. "Summarize the research paper I shared"
- User references a shared document.
- Intent: ['private_search'] with skipSearch: false
4. "Summarize" (WRONG to use private_search if no files/URLs)
- No context provided, no files uploaded.
- Correct: Skip this intent, let the answer agent ask what to summarize
5. "What does my document say about climate change and also search the web for recent updates?"
- Combine private document search with web search.
- Intent: ['private_search', 'web_search'] with skipSearch: false
**IMPORTANT**: Only use this intent if files are actually uploaded or URLs are explicitly provided in the query. Check the context for uploaded files before selecting this intent. Always set skipSearch to false when using this intent.
**NOTE**: This intent can be combined with other search intents when the user wants both personal document information and external sources.`;
const privateSearchIntent: Intent = {
name: 'private_search',
description,
enabled: (config) => true,
requiresSearch: true,
};
export default privateSearchIntent;

View File

@@ -1,31 +0,0 @@
import { Intent, SearchAgentConfig, SearchSources } from '../../types';
class IntentRegistry {
private static intents = new Map<string, Intent>();
static register(intent: Intent) {
this.intents.set(intent.name, intent);
}
static get(name: string): Intent | undefined {
return this.intents.get(name);
}
static getAvailableIntents(config: { sources: SearchSources[] }): Intent[] {
return Array.from(
this.intents.values().filter((intent) => intent.enabled(config)),
);
}
static getDescriptions(config: { sources: SearchSources[] }): string {
const availableintents = this.getAvailableIntents(config);
return availableintents
.map(
(intent) => `-------\n\n###${intent.name}: ${intent.description}\n\n`,
)
.join('\n\n');
}
}
export default IntentRegistry;

View File

@@ -1,31 +0,0 @@
import { Intent } from '../../types';
const description = `
Use this intent to find current information from the web when the user is asking a question or needs up-to-date information that cannot be provided by widgets or other intents.
#### When to use:
1. Simple user questions about current events, news, weather, or general knowledge that require the latest information and there is no specific better intent to use.
2. When the user explicitly requests information from the web or indicates they want the most recent data (and still there's no other better intent).
3. When no widgets can fully satisfy the user's request for information nor any other specialized search intent applies.
#### Examples use cases:
1. "What is the weather in San Francisco today? ALso tell me some popular events happening there this weekend."
- In this case, the weather widget can provide the current weather, but for popular events, a web search is needed. So the intent should include a 'web_search' & a 'widget_response'.
2. "Who won the Oscar for Best Picture in 2024?"
- This is a straightforward question that requires current information from the web.
3. "Give me the latest news on AI regulations."
- The user is asking for up-to-date news, which necessitates a web search.
**IMPORTANT**: If this intent is given then skip search should be false.
`;
const webSearchIntent: Intent = {
name: 'web_search',
description: description,
requiresSearch: true,
enabled: (config) => config.sources.includes('web'),
};
export default webSearchIntent;

View File

@@ -1,47 +0,0 @@
import { Intent } from '../../types';
const description = `Use this intent when the user's query can be fully or partially answered using specialized widgets that provide structured, real-time data (weather, stocks, calculations, and more).
#### When to use:
1. The user is asking for specific information that a widget can provide (current weather, stock prices, mathematical calculations, unit conversions, etc.).
2. A widget can completely answer the query without needing additional web search (use this intent alone and set skipSearch to true).
3. A widget can provide part of the answer, but additional information from web search or other sources is needed (combine with other intents like 'web_search' and set skipSearch to false).
#### Example use cases:
Note: These are just examples - there are several other widgets available for use depending on the user's query.
1. "What is the weather in New York?"
- The weather widget can fully answer this query.
- Intent: ['widget_response'] with skipSearch: true
- Widget: [{ type: 'weather', location: 'New York', lat: 0, lon: 0 }]
2. "What's the weather in San Francisco today? Also tell me some popular events happening there this weekend."
- Weather widget provides current conditions, but events require web search.
- Intent: ['web_search', 'widget_response'] with skipSearch: false
- Widget: [{ type: 'weather', location: 'San Francisco', lat: 0, lon: 0 }]
3. "Calculate 25% of 480"
- The calculator widget can fully answer this.
- Intent: ['widget_response'] with skipSearch: true
- Widget: [{ type: 'calculator', expression: '25% of 480' }]
4. "AAPL stock price and recent Apple news"
- Stock widget provides price, but news requires web search.
- Intent: ['web_search', 'widget_response'] with skipSearch: false
- Widget: [{ type: 'stock', symbol: 'AAPL' }]
5. "What's Tesla's stock doing and how does it compare to competitors?"
- Stock widget provides Tesla's price, but comparison analysis requires web search.
- Intent: ['web_search', 'widget_response'] with skipSearch: false
- Widget: [{ type: 'stock', symbol: 'TSLA' }]
**IMPORTANT**: Set skipSearch to true ONLY if the widget(s) can completely answer the user's query without any additional information. If the user asks for anything beyond what the widget provides (context, explanations, comparisons, related information), combine this intent with 'web_search' and set skipSearch to false.`;
const widgetResponseIntent: Intent = {
name: 'widget_response',
description,
requiresSearch: false,
enabled: (config) => true,
};
export default widgetResponseIntent;

View File

@@ -1,53 +0,0 @@
import { Intent } from '../../types';
const description = `Use this intent for simple writing or greeting tasks that do not require any external information or facts. This is ONLY for greetings and straightforward creative writing that needs no factual verification.
#### When to use:
1. User greetings or simple social interactions (hello, hi, thanks, goodbye).
2. Creative writing tasks that require NO factual information (poems, birthday messages, thank you notes).
3. Simple drafting tasks where the user provides all necessary information.
#### When NOT to use:
1. ANY question that starts with "what", "how", "why", "when", "where", "who" - these need web_search.
2. Requests for explanations, definitions, or information about anything.
3. Code-related questions or technical help - these need web_search.
4. Writing tasks that require facts, data, or current information.
5. When you're uncertain about any information needed - default to web_search.
#### Example use cases:
1. "Hello" or "Hi there"
- Simple greeting, no information needed.
- Intent: ['writing_task'] with skipSearch: true
2. "Write me a birthday message for my friend"
- Creative writing, no facts needed.
- Intent: ['writing_task'] with skipSearch: true
3. "Draft a thank you email for a job interview"
- Simple writing task, no external information required.
- Intent: ['writing_task'] with skipSearch: true
4. "What is React?" (WRONG to use writing_task)
- This is a QUESTION asking for information.
- Correct intent: ['web_search'] with skipSearch: false
5. "How do I fix this error in Python?" (WRONG to use writing_task)
- This is asking for technical help.
- Correct intent: ['web_search'] with skipSearch: false
6. "Write an email about the latest AI developments" (WRONG to use writing_task alone)
- This requires current information about AI developments.
- Correct intent: ['web_search'] with skipSearch: false
**CRITICAL RULE**: When in doubt, DO NOT use this intent. Default to web_search. This intent should be rare - only use it for greetings and purely creative writing tasks that need absolutely no facts or information.
**IMPORTANT**: If this intent is used alone, skipSearch should be true. Never combine this with other search intents unless you're absolutely certain both are needed.`;
const writingTaskIntent: Intent = {
name: 'writing_task',
description,
requiresSearch: false,
enabled: (config) => true,
};
export default writingTaskIntent;

View File

@@ -55,10 +55,15 @@ export type ClassifierInput = {
}; };
export type ClassifierOutput = { export type ClassifierOutput = {
classification: {
skipSearch: boolean; skipSearch: boolean;
personalSearch: boolean;
academicSearch: boolean;
discussionSearch: boolean;
showWeatherWidget: boolean;
showStockWidget: boolean;
};
standaloneFollowUp: string; standaloneFollowUp: string;
intents: string[];
widgets: WidgetConfig[];
}; };
export type AdditionalConfig = { export type AdditionalConfig = {

View File

@@ -1,202 +1,59 @@
export const getClassifierPrompt = (input: { export const classifierPrompt = `
intentDesc: string;
widgetDesc: string;
}) => {
return `
<role> <role>
You are an expert query classifier for an AI-powered search engine. Your task is to analyze user queries and determine the optimal strategy to answer them—selecting the right search intent(s) and widgets that will render in the UI. Assistant is an advanced AI system designed to analyze the user query and the conversation history to determine the most appropriate classification for the search operation.
It will be shared a detailed conversation history and a user query and it has to classify the query based on the guidelines and label definitions provided. You also have to generate a standalone follow-up question that is self-contained and context-independent.
</role> </role>
<task> <labels>
Given a conversation history and follow-up question, you must: NOTE: BY GENERAL KNOWLEDGE WE MEAN INFORMATION THAT IS OBVIOUS, WIDELY KNOWN, OR CAN BE INFERRED WITHOUT EXTERNAL SOURCES FOR EXAMPLE MATHEMATICAL FACTS, BASIC SCIENTIFIC KNOWLEDGE, COMMON HISTORICAL EVENTS, ETC.
1. Determine if search should be skipped (skipSearch: boolean) 1. skipSearch (boolean): Deeply analyze whether the user's query can be answered without performing any search.
2. Generate a standalone, self-contained version of the question (standaloneFollowUp: string) - Set it to true if the query is straightforward, factual, or can be answered based on general knowledge.
3. Identify the intent(s) that describe how to fulfill the query (intent: array) - Set it to true for writing tasks or greeting messages that do not require external information.
4. Select appropriate widgets that will enhance the UI response (widgets: array) - Set it to true if weather, stock, or similar widgets can fully satisfy the user's request.
</task> - Set it to false if the query requires up-to-date information, specific details, or context that cannot be inferred from general knowledge.
- ALWAYS SET SKIPSEARCH TO FALSE IF YOU ARE UNCERTAIN OR IF THE QUERY IS AMBIGUOUS OR IF YOU'RE NOT SURE.
2. personalSearch (boolean): Determine if the query requires searching through user uploaded documents.
- Set it to true if the query explicitly references or implies the need to access user-uploaded documents for example "Determine the key points from the document I uploaded about..." or "Who is the author?", "Summarize the content of the document"
- Set it to false if the query does not reference user-uploaded documents or if the information can be obtained through general web search.
- ALWAYS SET PERSONALSEARCH TO FALSE IF YOU ARE UNCERTAIN OR IF THE QUERY IS AMBIGUOUS OR IF YOU'RE NOT SURE. AND SET SKIPSEARCH TO FALSE AS WELL.
3. academicSearch (boolean): Assess whether the query requires searching academic databases or scholarly articles.
- Set it to true if the query explicitly requests scholarly information, research papers, academic articles, or citations for example "Find recent studies on...", "What does the latest research say about...", or "Provide citations for..."
- Set it to false if the query can be answered through general web search or does not specifically request academic sources.
4. discussionSearch (boolean): Evaluate if the query necessitates searching through online forums, discussion boards, or community Q&A platforms.
- Set it to true if the query seeks opinions, personal experiences, community advice, or discussions for example "What do people think about...", "Are there any discussions on...", or "What are the common issues faced by..."
- Set it to true if they're asking for reviews or feedback from users on products, services, or experiences.
- Set it to false if the query can be answered through general web search or does not specifically request information from discussion platforms.
5. showWeatherWidget (boolean): Decide if displaying a weather widget would adequately address the user's query.
- Set it to true if the user's query is specifically about current weather conditions, forecasts, or any weather-related information for a particular location.
- Set it to true for queries like "What's the weather like in [Location]?" or "Will it rain tomorrow in [Location]?" or "Show me the weather" (Here they mean weather of their current location).
- If it can fully answer the user query without needing additional search, set skipSearch to true as well.
6. showStockWidget (boolean): Determine if displaying a stock market widget would sufficiently fulfill the user's request.
- Set it to true if the user's query is specifically about current stock prices or stock related information for particular companies. Never use it for a market analysis or news about stock market.
- Set it to true for queries like "What's the stock price of [Company]?" or "How is the [Stock] performing today?" or "Show me the stock prices" (Here they mean stocks of companies they are interested in).
- If it can fully answer the user query without needing additional search, set skipSearch to true as well.
</labels>
## Understanding Your Tools <standalone_followup>
For the standalone follow up, you have to generate a self contained, context independant reformulation of the user's query.
You basically have to rephrase the user's query in a way that it can be understood without any prior context from the conversation history.
Say for example the converastion is about cars and the user says "How do they work" then the standalone follow up should be "How do cars work?"
**Intents** define HOW to find or generate information: Do not contain excess information or everything that has been discussed before, just reformulate the user's last query in a self contained manner.
- Different search methods: web search, forum discussions, academic papers, personal documents The standalone follow-up should be concise and to the point.
- Generation methods: direct response for greetings, creative writing </standalone_followup>
- Each intent represents a different approach to answering the query
- Multiple intents can be combined for comprehensive answers
**Widgets** are UI components that render structured, real-time data: <output_format>
- They display specific types of information (weather forecasts, calculations, stock prices, etc.) You must respond in the following JSON format without any extra text, explanations or filler sentences:
- They provide interactive, visual elements that enhance the text response
- They fetch data independently and render directly in the interface
- They can work alone (widget-only answers) or alongside search results
**Key distinction:** Intents determine the search/generation strategy, while widgets provide visual data enhancements in the UI.
## The Philosophy of skipSearch
Search connects you to external knowledge sources. Skip it only when external knowledge isn't needed.
**Skip search (TRUE) when:**
- Widgets alone can fully answer the query with their structured data
- Simple greetings or social pleasantries
- Pure creative writing requiring absolutely zero facts
**Use search (FALSE) when:**
- User is asking a question (what, how, why, when, where, who)
- Any facts, explanations, or information are requested
- Technical help, code, or learning content is needed
- Current events, news, or time-sensitive information required
- Widgets provide partial data but context/explanation needed
- Uncertain - always default to searching
**Critical rule:** If the user is ASKING about something or requesting INFORMATION, they need search. Question words (what, how, why, explain, tell me) strongly indicate skipSearch should be FALSE.
## How Intents Work
Available intent options:
${input.intentDesc}
**Understanding intent descriptions:**
- Each intent description explains what it does and when to use it
- Read the descriptions carefully to understand their purpose
- Match user needs to the appropriate intent(s)
- Can select multiple intents for comprehensive coverage
**Selection strategy:**
1. Identify what the user is asking for
2. Review intent descriptions to find matches
3. Select all relevant intents (can combine multiple)
4. If user explicitly mentions a source (Reddit, research papers), use that specific intent
5. Default to general web search for broad questions
## How Widgets Work
Available widget options:
${input.widgetDesc}
**Understanding widget descriptions:**
- Each widget description explains what data it provides and how to use it
- Widgets render as UI components alongside the text response
- They enhance answers with visual, structured information
- Review descriptions to identify applicable widgets
**Selection strategy:**
1. Identify if query needs any structured/real-time data
2. Check widget descriptions for matches
3. Include ALL applicable widgets (each type only once)
4. Widgets work independently - include them even when also searching
**Important widget behaviors:**
- If widget fully answers query → skipSearch: TRUE, include widget, use widget_response intent
- If widget provides partial data → skipSearch: FALSE, include widget + appropriate search intent(s)
- Widgets and search intents coexist - they serve different purposes
## Making Queries Standalone
Transform follow-up questions to be understandable without conversation history:
**Replace vague references:**
- "it", "that", "this" → specific subjects from context
- "they", "those" → actual entities being discussed
- "the previous one" → the actual item from history
**Add necessary context:**
- Include the topic being discussed
- Reference specific subjects mentioned earlier
- Preserve original meaning and scope
- Don't over-elaborate or change intent
**Example transformations:**
- Context: Discussing React framework
- Follow-up: "How does it work?" → Standalone: "How does React work?"
- Follow-up: "What about hooks?" → Standalone: "What about React hooks?"
## Critical Decision Framework
Follow this decision tree IN ORDER:
### 1. Widget-Only Queries
**When:** Query can be fully answered by widget data alone
**Then:** skipSearch: TRUE, intent: ['widget_response'], include widget(s)
**Pattern:** Weather requests, calculations, unit conversions, stock prices (when no additional info needed)
### 2. Greeting/Simple Writing Tasks
**When:** Just greetings OR pure creative writing with zero factual requirements
**Then:** skipSearch: TRUE, intent: ['writing_task']
**Pattern:** "hello", "hi", "write a birthday message", "compose a poem"
**NEVER for:** Questions, explanations, definitions, facts, code help
### 3. Widget + Additional Information
**When:** Widget provides data but user wants more context/explanation
**Then:** skipSearch: FALSE, intent: ['appropriate_search', 'widget_response'], include widget(s)
**Pattern:** "weather in NYC and things to do", "AAPL stock and recent news"
### 4. Pure Search Queries
**When:** No widgets apply, just information/facts needed
**Then:** skipSearch: FALSE, select appropriate search intent(s)
**Strategy:**
- Default to general web search
- Use discussion search when user mentions Reddit, forums, opinions
- Use academic search when user mentions research, papers, studies
- Use private search when user references uploaded files/URLs
- Can combine multiple search intents
### 5. Think Before Setting skipSearch to TRUE
**Ask yourself:**
- Is the user ASKING about something? → FALSE
- Is the user requesting INFORMATION? → FALSE
- Is there ANY factual component? → FALSE
- Am I uncertain? → FALSE (default to search)
## Intent Selection Rules
Available intents:
${input.intentDesc}
**Rules:**
- Include at least one intent when applicable
- For information requests: default to general web search unless user specifies otherwise
- Use specialized search intents when explicitly requested (discussions, academic, private)
- Can combine multiple intents: ['academic_search', 'web_search']
- widget_response: when widgets fully satisfy the query
- writing_task: ONLY for greetings and simple creative writing (never for questions)
## Widget Selection Rules
Available widgets:
${input.widgetDesc}
**Rules:**
- Include ALL applicable widgets regardless of skipSearch value
- Each widget type can only be included once per query
- Widgets render in the UI to enhance responses with structured data
- Follow widget descriptions for proper parameter formatting
## Output Format
Your classification must be valid JSON:
\`\`\`json
{ {
"skipSearch": <true|false>, "classification": {
"standaloneFollowUp": "<self-contained, contextualized query>", "skipSearch": boolean,
"intent": ["<intent1>", "<intent2>"], "personalSearch": boolean,
"widgets": [ "academicSearch": boolean,
{ "discussionSearch": boolean,
"type": "<widget_type>", "showWeatherWidget": boolean,
"<param1>": "<value1>", "showStockWidget": boolean
"<param2>": "<value2>" },
} "standaloneFollowUp": string
]
} }
\`\`\` </output_format>
## Final Reminders
- **Intents** = HOW to answer (search strategy, generation type)
- **Widgets** = WHAT to display in UI (structured visual data)
- **skipSearch** = Can answer without external search? (widgets alone, greetings, pure creativity)
- **Default to FALSE** = When uncertain, search - better to search unnecessarily than miss information
- **Read descriptions** = Intent and widget descriptions contain all the information you need to select them properly
Your goal is to understand user intent and route requests through the optimal combination of search methods (intents) and UI enhancements (widgets). Pay close attention to what the user is actually asking for, not just pattern matching keywords.
`; `;
};