From 0a62c60da2d736b71cbe3ec060763ac264d67f41 Mon Sep 17 00:00:00 2001 From: ItzCrazyKns <95534749+ItzCrazyKns@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:35:00 +0530 Subject: [PATCH] feat(widgets): add LLM context to prevent context overflow --- src/lib/agents/search/index.ts | 3 +- src/lib/agents/search/types.ts | 1 + .../search/widgets/calculationWidget.ts | 2 + src/lib/agents/search/widgets/stockWidget.ts | 173 +++++++++--------- .../agents/search/widgets/weatherWidget.ts | 4 + 5 files changed, 99 insertions(+), 84 deletions(-) diff --git a/src/lib/agents/search/index.ts b/src/lib/agents/search/index.ts index bacdb88..ab12bfe 100644 --- a/src/lib/agents/search/index.ts +++ b/src/lib/agents/search/index.ts @@ -65,14 +65,13 @@ class SearchAgent { const widgetContext = widgetOutputs .map((o) => { - return `${o.type}: ${JSON.stringify(o.data)}`; + return `${o.type}: ${o.llmContext}`; }) .join('\n-------------\n'); const finalContextWithWidgets = `${finalContext}\n${widgetContext}`; const writerPrompt = getWriterPrompt(finalContextWithWidgets); - const answerStream = input.config.llm.streamText({ messages: [ { diff --git a/src/lib/agents/search/types.ts b/src/lib/agents/search/types.ts index 421ee7f..82900c5 100644 --- a/src/lib/agents/search/types.ts +++ b/src/lib/agents/search/types.ts @@ -43,6 +43,7 @@ export type WidgetConfig = { export type WidgetOutput = { type: string; + llmContext: string; data: any; }; diff --git a/src/lib/agents/search/widgets/calculationWidget.ts b/src/lib/agents/search/widgets/calculationWidget.ts index c613b40..1c1ba51 100644 --- a/src/lib/agents/search/widgets/calculationWidget.ts +++ b/src/lib/agents/search/widgets/calculationWidget.ts @@ -45,6 +45,7 @@ const calculationWidget: Widget = { return { type: 'calculation_result', + llmContext: `The result of the expression "${params.expression}" is ${result}.`, data: { expression: params.expression, result: result, @@ -53,6 +54,7 @@ const calculationWidget: Widget = { } catch (error) { return { type: 'calculation_result', + llmContext: 'Failed to evaluate mathematical expression.', data: { expression: params.expression, result: `Error evaluating expression: ${error}`, diff --git a/src/lib/agents/search/widgets/stockWidget.ts b/src/lib/agents/search/widgets/stockWidget.ts index b4f8b86..c18b734 100644 --- a/src/lib/agents/search/widgets/stockWidget.ts +++ b/src/lib/agents/search/widgets/stockWidget.ts @@ -286,120 +286,129 @@ You can set skipSearch to true if the stock widget can fully answer the user's q chartData: { '1D': chart1D ? { - timestamps: chart1D.quotes.map((q: any) => q.date.getTime()), - prices: chart1D.quotes.map((q: any) => q.close), - } + timestamps: chart1D.quotes.map((q: any) => q.date.getTime()), + prices: chart1D.quotes.map((q: any) => q.close), + } : null, '5D': chart5D ? { - timestamps: chart5D.quotes.map((q: any) => q.date.getTime()), - prices: chart5D.quotes.map((q: any) => q.close), - } + timestamps: chart5D.quotes.map((q: any) => q.date.getTime()), + prices: chart5D.quotes.map((q: any) => q.close), + } : null, '1M': chart1M ? { - timestamps: chart1M.quotes.map((q: any) => q.date.getTime()), - prices: chart1M.quotes.map((q: any) => q.close), - } + timestamps: chart1M.quotes.map((q: any) => q.date.getTime()), + prices: chart1M.quotes.map((q: any) => q.close), + } : null, '3M': chart3M ? { - timestamps: chart3M.quotes.map((q: any) => q.date.getTime()), - prices: chart3M.quotes.map((q: any) => q.close), - } + timestamps: chart3M.quotes.map((q: any) => q.date.getTime()), + prices: chart3M.quotes.map((q: any) => q.close), + } : null, '6M': chart6M ? { - timestamps: chart6M.quotes.map((q: any) => q.date.getTime()), - prices: chart6M.quotes.map((q: any) => q.close), - } + timestamps: chart6M.quotes.map((q: any) => q.date.getTime()), + prices: chart6M.quotes.map((q: any) => q.close), + } : null, '1Y': chart1Y ? { - timestamps: chart1Y.quotes.map((q: any) => q.date.getTime()), - prices: chart1Y.quotes.map((q: any) => q.close), - } + timestamps: chart1Y.quotes.map((q: any) => q.date.getTime()), + prices: chart1Y.quotes.map((q: any) => q.close), + } : null, MAX: chartMAX ? { - timestamps: chartMAX.quotes.map((q: any) => q.date.getTime()), - prices: chartMAX.quotes.map((q: any) => q.close), - } + timestamps: chartMAX.quotes.map((q: any) => q.date.getTime()), + prices: chartMAX.quotes.map((q: any) => q.close), + } : null, }, comparisonData: comparisonData ? comparisonData.map((comp: any) => ({ - ticker: comp.ticker, - name: comp.name, - chartData: { - '1D': comp.charts[0] - ? { - timestamps: comp.charts[0].quotes.map((q: any) => - q.date.getTime(), - ), - prices: comp.charts[0].quotes.map((q: any) => q.close), - } - : null, - '5D': comp.charts[1] - ? { - timestamps: comp.charts[1].quotes.map((q: any) => - q.date.getTime(), - ), - prices: comp.charts[1].quotes.map((q: any) => q.close), - } - : null, - '1M': comp.charts[2] - ? { - timestamps: comp.charts[2].quotes.map((q: any) => - q.date.getTime(), - ), - prices: comp.charts[2].quotes.map((q: any) => q.close), - } - : null, - '3M': comp.charts[3] - ? { - timestamps: comp.charts[3].quotes.map((q: any) => - q.date.getTime(), - ), - prices: comp.charts[3].quotes.map((q: any) => q.close), - } - : null, - '6M': comp.charts[4] - ? { - timestamps: comp.charts[4].quotes.map((q: any) => - q.date.getTime(), - ), - prices: comp.charts[4].quotes.map((q: any) => q.close), - } - : null, - '1Y': comp.charts[5] - ? { - timestamps: comp.charts[5].quotes.map((q: any) => - q.date.getTime(), - ), - prices: comp.charts[5].quotes.map((q: any) => q.close), - } - : null, - MAX: comp.charts[6] - ? { - timestamps: comp.charts[6].quotes.map((q: any) => - q.date.getTime(), - ), - prices: comp.charts[6].quotes.map((q: any) => q.close), - } - : null, - }, - })) + ticker: comp.ticker, + name: comp.name, + chartData: { + '1D': comp.charts[0] + ? { + timestamps: comp.charts[0].quotes.map((q: any) => + q.date.getTime(), + ), + prices: comp.charts[0].quotes.map((q: any) => q.close), + } + : null, + '5D': comp.charts[1] + ? { + timestamps: comp.charts[1].quotes.map((q: any) => + q.date.getTime(), + ), + prices: comp.charts[1].quotes.map((q: any) => q.close), + } + : null, + '1M': comp.charts[2] + ? { + timestamps: comp.charts[2].quotes.map((q: any) => + q.date.getTime(), + ), + prices: comp.charts[2].quotes.map((q: any) => q.close), + } + : null, + '3M': comp.charts[3] + ? { + timestamps: comp.charts[3].quotes.map((q: any) => + q.date.getTime(), + ), + prices: comp.charts[3].quotes.map((q: any) => q.close), + } + : null, + '6M': comp.charts[4] + ? { + timestamps: comp.charts[4].quotes.map((q: any) => + q.date.getTime(), + ), + prices: comp.charts[4].quotes.map((q: any) => q.close), + } + : null, + '1Y': comp.charts[5] + ? { + timestamps: comp.charts[5].quotes.map((q: any) => + q.date.getTime(), + ), + prices: comp.charts[5].quotes.map((q: any) => q.close), + } + : null, + MAX: comp.charts[6] + ? { + timestamps: comp.charts[6].quotes.map((q: any) => + q.date.getTime(), + ), + prices: comp.charts[6].quotes.map((q: any) => q.close), + } + : null, + }, + })) : null, }; return { 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, }; } catch (error: any) { return { type: 'stock', + llmContext: 'Failed to fetch stock data.', data: { error: `Error fetching stock data: ${error.message || error}`, ticker: params.ticker, diff --git a/src/lib/agents/search/widgets/weatherWidget.ts b/src/lib/agents/search/widgets/weatherWidget.ts index 4b2dcf9..3d78df3 100644 --- a/src/lib/agents/search/widgets/weatherWidget.ts +++ b/src/lib/agents/search/widgets/weatherWidget.ts @@ -94,6 +94,7 @@ You can set skipSearch to true if the weather widget can fully answer the user's return { type: 'weather', + llmContext: `Weather in ${params.location} is ${weatherData.current}`, data: { location: params.location, latitude: location.lat, @@ -138,6 +139,7 @@ You can set skipSearch to true if the weather widget can fully answer the user's return { type: 'weather', + llmContext: `Weather in ${locationData.display_name} is ${weatherData.current}`, data: { location: locationData.display_name, latitude: params.lat, @@ -159,11 +161,13 @@ You can set skipSearch to true if the weather widget can fully answer the user's return { type: 'weather', + llmContext: 'No valid location or coordinates provided.', data: null, }; } catch (err) { return { type: 'weather', + llmContext: 'Failed to fetch weather data.', data: { error: `Error fetching weather data: ${err}`, },