feat(widgets): add LLM context to prevent context overflow

This commit is contained in:
ItzCrazyKns
2025-11-24 15:35:00 +05:30
parent 956a768a86
commit 0a62c60da2
5 changed files with 99 additions and 84 deletions

View File

@@ -65,14 +65,13 @@ class SearchAgent {
const widgetContext = widgetOutputs const widgetContext = widgetOutputs
.map((o) => { .map((o) => {
return `${o.type}: ${JSON.stringify(o.data)}`; return `${o.type}: ${o.llmContext}`;
}) })
.join('\n-------------\n'); .join('\n-------------\n');
const finalContextWithWidgets = `<search_results note="These are the search results and you can cite these">${finalContext}</search_results>\n<widgets_result noteForAssistant="Its output is already showed to the user, you can use this information to answer the query but do not CITE this as a souce">${widgetContext}</widgets_result>`; const finalContextWithWidgets = `<search_results note="These are the search results and you can cite these">${finalContext}</search_results>\n<widgets_result noteForAssistant="Its output is already showed to the user, you can use this information to answer the query but do not CITE this as a souce">${widgetContext}</widgets_result>`;
const writerPrompt = getWriterPrompt(finalContextWithWidgets); const writerPrompt = getWriterPrompt(finalContextWithWidgets);
const answerStream = input.config.llm.streamText({ const answerStream = input.config.llm.streamText({
messages: [ messages: [
{ {

View File

@@ -43,6 +43,7 @@ export type WidgetConfig = {
export type WidgetOutput = { export type WidgetOutput = {
type: string; type: string;
llmContext: string;
data: any; data: any;
}; };

View File

@@ -45,6 +45,7 @@ const calculationWidget: Widget<typeof schema> = {
return { return {
type: 'calculation_result', type: 'calculation_result',
llmContext: `The result of the expression "${params.expression}" is ${result}.`,
data: { data: {
expression: params.expression, expression: params.expression,
result: result, result: result,
@@ -53,6 +54,7 @@ const calculationWidget: Widget<typeof schema> = {
} catch (error) { } catch (error) {
return { return {
type: 'calculation_result', type: 'calculation_result',
llmContext: 'Failed to evaluate mathematical expression.',
data: { data: {
expression: params.expression, expression: params.expression,
result: `Error evaluating expression: ${error}`, result: `Error evaluating expression: ${error}`,

View File

@@ -286,120 +286,129 @@ You can set skipSearch to true if the stock widget can fully answer the user's q
chartData: { chartData: {
'1D': chart1D '1D': chart1D
? { ? {
timestamps: chart1D.quotes.map((q: any) => q.date.getTime()), timestamps: chart1D.quotes.map((q: any) => q.date.getTime()),
prices: chart1D.quotes.map((q: any) => q.close), prices: chart1D.quotes.map((q: any) => q.close),
} }
: null, : null,
'5D': chart5D '5D': chart5D
? { ? {
timestamps: chart5D.quotes.map((q: any) => q.date.getTime()), timestamps: chart5D.quotes.map((q: any) => q.date.getTime()),
prices: chart5D.quotes.map((q: any) => q.close), prices: chart5D.quotes.map((q: any) => q.close),
} }
: null, : null,
'1M': chart1M '1M': chart1M
? { ? {
timestamps: chart1M.quotes.map((q: any) => q.date.getTime()), timestamps: chart1M.quotes.map((q: any) => q.date.getTime()),
prices: chart1M.quotes.map((q: any) => q.close), prices: chart1M.quotes.map((q: any) => q.close),
} }
: null, : null,
'3M': chart3M '3M': chart3M
? { ? {
timestamps: chart3M.quotes.map((q: any) => q.date.getTime()), timestamps: chart3M.quotes.map((q: any) => q.date.getTime()),
prices: chart3M.quotes.map((q: any) => q.close), prices: chart3M.quotes.map((q: any) => q.close),
} }
: null, : null,
'6M': chart6M '6M': chart6M
? { ? {
timestamps: chart6M.quotes.map((q: any) => q.date.getTime()), timestamps: chart6M.quotes.map((q: any) => q.date.getTime()),
prices: chart6M.quotes.map((q: any) => q.close), prices: chart6M.quotes.map((q: any) => q.close),
} }
: null, : null,
'1Y': chart1Y '1Y': chart1Y
? { ? {
timestamps: chart1Y.quotes.map((q: any) => q.date.getTime()), timestamps: chart1Y.quotes.map((q: any) => q.date.getTime()),
prices: chart1Y.quotes.map((q: any) => q.close), prices: chart1Y.quotes.map((q: any) => q.close),
} }
: null, : null,
MAX: chartMAX MAX: chartMAX
? { ? {
timestamps: chartMAX.quotes.map((q: any) => q.date.getTime()), timestamps: chartMAX.quotes.map((q: any) => q.date.getTime()),
prices: chartMAX.quotes.map((q: any) => q.close), prices: chartMAX.quotes.map((q: any) => q.close),
} }
: null, : null,
}, },
comparisonData: comparisonData comparisonData: comparisonData
? comparisonData.map((comp: any) => ({ ? comparisonData.map((comp: any) => ({
ticker: comp.ticker, ticker: comp.ticker,
name: comp.name, name: comp.name,
chartData: { chartData: {
'1D': comp.charts[0] '1D': comp.charts[0]
? { ? {
timestamps: comp.charts[0].quotes.map((q: any) => timestamps: comp.charts[0].quotes.map((q: any) =>
q.date.getTime(), q.date.getTime(),
), ),
prices: comp.charts[0].quotes.map((q: any) => q.close), prices: comp.charts[0].quotes.map((q: any) => q.close),
} }
: null, : null,
'5D': comp.charts[1] '5D': comp.charts[1]
? { ? {
timestamps: comp.charts[1].quotes.map((q: any) => timestamps: comp.charts[1].quotes.map((q: any) =>
q.date.getTime(), q.date.getTime(),
), ),
prices: comp.charts[1].quotes.map((q: any) => q.close), prices: comp.charts[1].quotes.map((q: any) => q.close),
} }
: null, : null,
'1M': comp.charts[2] '1M': comp.charts[2]
? { ? {
timestamps: comp.charts[2].quotes.map((q: any) => timestamps: comp.charts[2].quotes.map((q: any) =>
q.date.getTime(), q.date.getTime(),
), ),
prices: comp.charts[2].quotes.map((q: any) => q.close), prices: comp.charts[2].quotes.map((q: any) => q.close),
} }
: null, : null,
'3M': comp.charts[3] '3M': comp.charts[3]
? { ? {
timestamps: comp.charts[3].quotes.map((q: any) => timestamps: comp.charts[3].quotes.map((q: any) =>
q.date.getTime(), q.date.getTime(),
), ),
prices: comp.charts[3].quotes.map((q: any) => q.close), prices: comp.charts[3].quotes.map((q: any) => q.close),
} }
: null, : null,
'6M': comp.charts[4] '6M': comp.charts[4]
? { ? {
timestamps: comp.charts[4].quotes.map((q: any) => timestamps: comp.charts[4].quotes.map((q: any) =>
q.date.getTime(), q.date.getTime(),
), ),
prices: comp.charts[4].quotes.map((q: any) => q.close), prices: comp.charts[4].quotes.map((q: any) => q.close),
} }
: null, : null,
'1Y': comp.charts[5] '1Y': comp.charts[5]
? { ? {
timestamps: comp.charts[5].quotes.map((q: any) => timestamps: comp.charts[5].quotes.map((q: any) =>
q.date.getTime(), q.date.getTime(),
), ),
prices: comp.charts[5].quotes.map((q: any) => q.close), prices: comp.charts[5].quotes.map((q: any) => q.close),
} }
: null, : null,
MAX: comp.charts[6] MAX: comp.charts[6]
? { ? {
timestamps: comp.charts[6].quotes.map((q: any) => timestamps: comp.charts[6].quotes.map((q: any) =>
q.date.getTime(), q.date.getTime(),
), ),
prices: comp.charts[6].quotes.map((q: any) => q.close), prices: comp.charts[6].quotes.map((q: any) => q.close),
} }
: null, : null,
}, },
})) }))
: null, : null,
}; };
return { return {
type: 'stock', type: 'stock',
llmContext: `Current price of ${stockData.shortName} (${stockData.symbol}) is ${stockData.regularMarketPrice} ${stockData.currency}. Other details: ${JSON.stringify({
marketState: stockData.marketState,
regularMarketChange: stockData.regularMarketChange,
regularMarketChangePercent: stockData.regularMarketChangePercent,
marketCap: stockData.marketCap,
peRatio: stockData.trailingPE,
dividendYield: stockData.dividendYield,
})}`,
data: stockData, data: stockData,
}; };
} catch (error: any) { } catch (error: any) {
return { return {
type: 'stock', type: 'stock',
llmContext: 'Failed to fetch stock data.',
data: { data: {
error: `Error fetching stock data: ${error.message || error}`, error: `Error fetching stock data: ${error.message || error}`,
ticker: params.ticker, ticker: params.ticker,

View File

@@ -94,6 +94,7 @@ You can set skipSearch to true if the weather widget can fully answer the user's
return { return {
type: 'weather', type: 'weather',
llmContext: `Weather in ${params.location} is ${weatherData.current}`,
data: { data: {
location: params.location, location: params.location,
latitude: location.lat, latitude: location.lat,
@@ -138,6 +139,7 @@ You can set skipSearch to true if the weather widget can fully answer the user's
return { return {
type: 'weather', type: 'weather',
llmContext: `Weather in ${locationData.display_name} is ${weatherData.current}`,
data: { data: {
location: locationData.display_name, location: locationData.display_name,
latitude: params.lat, latitude: params.lat,
@@ -159,11 +161,13 @@ You can set skipSearch to true if the weather widget can fully answer the user's
return { return {
type: 'weather', type: 'weather',
llmContext: 'No valid location or coordinates provided.',
data: null, data: null,
}; };
} catch (err) { } catch (err) {
return { return {
type: 'weather', type: 'weather',
llmContext: 'Failed to fetch weather data.',
data: { data: {
error: `Error fetching weather data: ${err}`, error: `Error fetching weather data: ${err}`,
}, },