From 975b9e4cbe3da06fa2c63ec65edfb97a64a39889 Mon Sep 17 00:00:00 2001 From: uu-z Date: Fri, 10 Jan 2025 15:33:49 +0800 Subject: [PATCH 1/4] improve workflow --- .editorconfig | 11 +++++ .prettierc | 5 +++ server.ts | 3 +- src/SentientAI.ts | 6 +-- src/agent.ts | 61 ++++++++++++++++----------- src/index.ts | 5 +-- src/llm.ts | 84 ++++++++++++++++++++++++++++--------- src/tools/weatherapi.ts | 2 +- src/workflow.ts | 92 ++++++++++++++--------------------------- tsconfig.json | 3 +- 10 files changed, 159 insertions(+), 113 deletions(-) create mode 100644 .editorconfig create mode 100644 .prettierc diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..09d7a33 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# https://EditorConfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.prettierc b/.prettierc new file mode 100644 index 0000000..f818907 --- /dev/null +++ b/.prettierc @@ -0,0 +1,5 @@ +{ + "printWidth": 120, + "tabWidth": 2, + "useTabs": false, +} diff --git a/server.ts b/server.ts index f464c85..c3fe4dc 100644 --- a/server.ts +++ b/server.ts @@ -25,9 +25,10 @@ app.post("/ask", async (c) => { return c.json({ error: "question is required." }, 400); } - const response = await sentai.agent.run(content); + const response = await sentai.agent.execute(content); return c.json({ data: response }); } catch (e) { + console.error(e); return c.json({ error: "Internal server error." }, 400); } }); diff --git a/src/SentientAI.ts b/src/SentientAI.ts index 73b536f..35d310f 100644 --- a/src/SentientAI.ts +++ b/src/SentientAI.ts @@ -9,7 +9,7 @@ export class SentientAI { weatherAgent = new Agent({ name: "Weather Agent", description: - "Get current weather with CurrentWeatherAPITool and forecast weather with ForecastWeatherAPITool.", + "Weather Agent is a tool that can hanlde all weather related requests.", tools: [ new CurrentWeatherAPITool(process.env.NUBILA_API_KEY!), new ForecastWeatherAPITool(process.env.OPENWEATHER_API_KEY!), @@ -18,7 +18,5 @@ export class SentientAI { newsTool = new NewsAPITool(process.env.NEWSAPI_API_KEY!); - agent = new Agent({ - tools: [this.weatherAgent, this.newsTool], - }); + agent = new Agent({ tools: [this.weatherAgent, this.newsTool] }); } diff --git a/src/agent.ts b/src/agent.ts index b0d1087..9648271 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -3,35 +3,48 @@ import { Tool } from "./tools/tool"; import { Memory } from "./memory"; import { Workflow } from "./workflow"; +interface PromptContext { + tool: Tool; + toolOutput: string; + toolInput: string; + input: string; +} + +export interface Agent { + name: string; + description: string; + tools: Tool[]; + prompt: (ctx: PromptContext) => string; +} + export class Agent { - name: string = ""; - description: string = ""; - tools: (Tool | Agent)[] = []; + tools: Tool[] = []; + workflow: Workflow; + + // support tempalte format + prompt = (ctx: PromptContext) => ` + User Input: ${ctx.input} + Tool Used: ${ctx.tool.name} + Tool Input: ${ctx.toolInput} + Tool Output: ${ctx.toolOutput} - private workflow: Workflow; + Generate a human-readable response based on the tool output${ctx.tool.twitterAccount ? ` and mention x handle ${ctx.tool.twitterAccount} in the end.` : ""}`; - constructor({ - name, - description, - fastllm, - llm, - tools, - memory, - }: { - name?: string; - description?: string; - fastllm?: LLM; - llm?: LLM; - tools: (Tool | Agent)[]; - memory?: Memory; - }) { - this.name = name || ""; - this.description = description || ""; - this.tools = tools; - this.workflow = new Workflow({ fastllm, llm, tools, memory }); + constructor(args: Partial = {}) { + Object.assign(this, args); + this.tools = this.tools.flatMap((i) => { + if (i instanceof Agent) { + return i.tools; + } + return i; + }); + if (!this.workflow) { + this.workflow = new Workflow({}); + } + this.workflow.agent = this; } - async run(input: string): Promise { + async execute(input: string): Promise { return this.workflow.execute(input); } } diff --git a/src/index.ts b/src/index.ts index 9680ea7..1d68539 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,8 +55,7 @@ async function runExample() { const newsTool = new NewsAPITool(newsApiKey); const tools: (Tool | Agent)[] = [weatherAgent, newsTool]; - const memory = new SimpleMemory(); - const agent = new Agent({ llm, tools, memory }); + const agent = new Agent({ tools }); const inputs = [ "Hello World", @@ -69,7 +68,7 @@ async function runExample() { for (const input of inputs) { console.log(`User Input: ${input}`); try { - const response = await agent.run(input); + const response = await agent.execute(input); console.log(`Agent Response: ${response}`); } catch (error) { console.error("Error running agent:", error); diff --git a/src/llm.ts b/src/llm.ts index 9ee0ba6..f672756 100644 --- a/src/llm.ts +++ b/src/llm.ts @@ -1,8 +1,8 @@ import OpenAI from "openai"; -import { RAGApplication, RAGApplicationBuilder } from '@llm-tools/embedjs'; -import { LibSqlDb } from '@llm-tools/embedjs-libsql'; - -import { OpenAiEmbeddings } from '@llm-tools/embedjs-openai'; +import { RAGApplication, RAGApplicationBuilder } from "@llm-tools/embedjs"; +import { LibSqlDb, LibSqlStore } from "@llm-tools/embedjs-libsql"; +import { OpenAi } from "@llm-tools/embedjs-openai"; +import { OpenAiEmbeddings } from "@llm-tools/embedjs-openai"; export interface LLM { generate(prompt: string): Promise; } @@ -21,7 +21,11 @@ export class OpenAILLM implements LLM { private openai: OpenAI; private model: string; - constructor(apiKey: string, model: string = "gpt-4") { // Default to gpt-4 + constructor( + apiKey: string = process.env.OPENAI_API_KEY!, + model: string = "gpt-4", + ) { + // Default to gpt-4 if (!apiKey) { throw new Error("OpenAI API key is required."); } @@ -40,16 +44,20 @@ export class OpenAILLM implements LLM { // Correctly access the message content const message = completion.choices?.[0]?.message; - if (message) { // Check if message exists + if (message) { + // Check if message exists return message.content?.trim() || "No content in message"; // Check if message.content exists } else { console.error("Unexpected OpenAI response format:", completion); // Log the full response return "No message in response"; } - } catch (error: any) { if (error.response) { - console.error("OpenAI API Error:", error.response.status, error.response.data); + console.error( + "OpenAI API Error:", + error.response.status, + error.response.data, + ); } else { console.error("OpenAI Error:", error.message); } @@ -58,26 +66,65 @@ export class OpenAILLM implements LLM { } } +export class OpenAIRAG implements LLM { + rag: RAGApplication | null = null; -export class EmbedLLM implements LLM { - model: RAGApplication | null = null + constructor(args: Partial = {}) { + Object.assign(this, args); + if (!this.rag) { + new RAGApplicationBuilder() + .setModel( + new OpenAi({ + model: "gpt-4", + }), + ) + .setEmbeddingModel( + new OpenAiEmbeddings({ + model: "text-embedding-3-small", + }), + ) + .setVectorDatabase(new LibSqlDb({ path: "./data.db" })) + .setStore(new LibSqlStore({ path: "./data.db" })) + .build() + .then((rag) => (this.rag = rag)); + } + } - constructor(args: Partial = {}) { - Object.assign(this, args) + async generate(prompt: string): Promise { + try { + const result = await this.rag?.query(prompt); + console.log(result); + return result?.content.trim() || "No content in response"; + } catch (error: any) { + console.error(" API Error:", error.message); + return ` API Error: ${error.message}`; + } + } +} + +export class FastLLM implements LLM { + model: RAGApplication | null = null; + + constructor(args: Partial = {}) { + Object.assign(this, args); if (!this.model) { new RAGApplicationBuilder() - .setEmbeddingModel(new OpenAiEmbeddings({ - model: 'text-embedding-3-small' - })) - .setVectorDatabase(new LibSqlDb({ path: './data.db' })) - .build().then(model => this.model = model) + .setModel(new OpenAi({ model: "gpt-3.5-turbo" })) + .setEmbeddingModel( + new OpenAiEmbeddings({ + model: "text-embedding-3-small", + }), + ) + .setVectorDatabase(new LibSqlDb({ path: "./data.db" })) + .build() + .then((model) => (this.model = model)); } } async generate(prompt: string): Promise { try { const result = await this.model?.query(prompt); - console.log(result) + console.log(result); return result?.content.trim() || "No content in response"; } catch (error: any) { console.error("Together API Error:", error.message); @@ -85,4 +132,3 @@ export class EmbedLLM implements LLM { } } } - diff --git a/src/tools/weatherapi.ts b/src/tools/weatherapi.ts index c551621..667fe17 100644 --- a/src/tools/weatherapi.ts +++ b/src/tools/weatherapi.ts @@ -166,7 +166,7 @@ export class ForecastWeatherAPITool implements Tool { const cityName = userInput.cityName; try { const response = await fetch( - `${this.baseUrl}?q=${cityName}&appid=${this.apiKey}` + `${this.baseUrl}?q=${cityName}&appid=${this.apiKey}`, ); const data: ForecastWeatherResponse = await response.json(); const weatherList = data?.list; diff --git a/src/workflow.ts b/src/workflow.ts index dab5dad..916d0f0 100644 --- a/src/workflow.ts +++ b/src/workflow.ts @@ -1,9 +1,8 @@ -import { EmbedLLM, LLM, OpenAILLM } from "./llm"; -import { Memory, SimpleMemory } from "./memory"; +import { FastLLM, LLM, OpenAILLM, OpenAIRAG } from "./llm"; import { Tool } from "./tools/tool"; import { Agent } from "./agent"; -interface ActionResult { +export interface ActionResult { tool?: Tool; output: string; } @@ -11,32 +10,27 @@ interface ActionResult { export class Workflow { fastllm: LLM; llm: LLM; - memory: Memory; - tools: (Tool | Agent)[]; - - constructor({ - fastllm, - llm, - memory, - tools, - }: { - fastllm?: LLM; - llm?: LLM; - memory?: Memory; - tools: (Tool | Agent)[]; - }) { - this.fastllm = fastllm || new EmbedLLM(); - this.llm = - llm || new OpenAILLM(process.env.OPENAI_API_KEY!, "gpt-3.5-turbo"); // Use gpt-3.5-turbo for cost-effectiveness - this.memory = memory || new SimpleMemory(); - this.tools = tools; + agent: Agent; + + constructor(args: Partial = {}) { + Object.assign(this, args); + if (!this.fastllm) { + this.fastllm = new FastLLM(); + } + if (!this.llm) { + this.llm = new OpenAIRAG(); + } } async execute(input: string): Promise { - const memoryVariables = this.memory.loadMemoryVariables(); - const availableTools = getAvailableTools(this.tools); + const availableTools = this.agent.tools.map((tool) => ({ + name: tool.name, + description: tool.description, + })); + + // TODO: retrieve data from vector database - const prompt = ` + const prompt = ` Input: ${input} Available Tools: ${JSON.stringify(availableTools)} @@ -50,9 +44,10 @@ export class Workflow { \`\`\` If no tool is needed, set "tool" to null. `; - + console.log("prompt:", prompt); try { const llmResponse = await this.fastllm.generate(prompt); + console.log("fast LLM raw response:", llmResponse); const action: ActionResult = this.parseLLMResponse(llmResponse); let output: string; @@ -62,21 +57,20 @@ export class Workflow { console.log("toolOutput:", toolOutput); // FEED TOOL OUTPUT BACK TO LLM - const finalPrompt = ` - Previous Conversation: ${JSON.stringify(this.memory.loadMemoryVariables().history)} - User Input: ${input} - Tool Used: ${action.tool.name} - Tool Input: ${action.output} - Tool Output: ${toolOutput} - - Generate a human-readable response based on the tool output${action.tool.twitterAccount ? ` and mention x handle ${action.tool.twitterAccount} in the end.` : ""}. - `; + // Previous Conversation: ${JSON.stringify(this.memory.loadMemoryVariables().history)} + const finalPrompt = this.agent.prompt({ + input, + tool: action.tool, + toolOutput, + toolInput: action.output, + }); output = await this.llm.generate(finalPrompt); } else { output = action.output; // LLM handles it directly (no tool used) } - this.memory.saveContext(input, output); + // this.memory.saveContext(input, output); + return output; } catch (error) { console.error("Workflow Error:", error); @@ -103,8 +97,7 @@ export class Workflow { } if (toolName) { - const allTools: Tool[] = getAllTools(this.tools); - const tool = allTools.find((t) => t.name === toolName); + const tool = this.agent.tools.find((t) => t.name === toolName); if (tool) { return { tool, output: toolInput }; } else { @@ -118,7 +111,7 @@ export class Workflow { "Error parsing LLM response:", error, "Raw LLM Response:", - llmResponse + llmResponse, ); return { output: `Error parsing LLM response: ${error}. Raw Response: ${llmResponse}.`, @@ -126,24 +119,3 @@ export class Workflow { } } } - -function getAvailableTools(tools: (Agent | Tool)[]): { - name: string; - description: string; -}[] { - return tools.flatMap((tool) => { - if (tool instanceof Agent) { - return getAvailableTools(tool.tools); - } - return [{ name: tool.name, description: tool.description }]; - }); -} - -function getAllTools(tools: (Agent | Tool)[]): Tool[] { - return tools.flatMap((tool) => { - if (tool instanceof Agent) { - return getAllTools(tool.tools); - } - return [tool]; - }); -} diff --git a/tsconfig.json b/tsconfig.json index cb8ca4c..ff0659f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "strict": true, "esModuleInterop": true, "skipLibCheck": true, + "strictPropertyInitialization": false, "forceConsistentCasingInFileNames": true, "rootDir": "./", "baseUrl": "./", @@ -13,4 +14,4 @@ "*": ["src/*"] } } -} \ No newline at end of file +} From 20c6bf0c1eff6922ad38a7fbb0706c372654a72d Mon Sep 17 00:00:00 2001 From: uu-z Date: Fri, 10 Jan 2025 15:34:38 +0800 Subject: [PATCH 2/4] clean up code --- src/workflow.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/workflow.ts b/src/workflow.ts index 916d0f0..5fce103 100644 --- a/src/workflow.ts +++ b/src/workflow.ts @@ -44,7 +44,6 @@ export class Workflow { \`\`\` If no tool is needed, set "tool" to null. `; - console.log("prompt:", prompt); try { const llmResponse = await this.fastllm.generate(prompt); From 91a9ef13605c221d9d012342b1f3602b828e91a1 Mon Sep 17 00:00:00 2001 From: uu-z Date: Fri, 10 Jan 2025 15:42:37 +0800 Subject: [PATCH 3/4] clean up code --- src/SentientAI.ts | 3 --- src/llm.ts | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/SentientAI.ts b/src/SentientAI.ts index 35d310f..748f208 100644 --- a/src/SentientAI.ts +++ b/src/SentientAI.ts @@ -7,9 +7,6 @@ import { export class SentientAI { weatherAgent = new Agent({ - name: "Weather Agent", - description: - "Weather Agent is a tool that can hanlde all weather related requests.", tools: [ new CurrentWeatherAPITool(process.env.NUBILA_API_KEY!), new ForecastWeatherAPITool(process.env.OPENWEATHER_API_KEY!), diff --git a/src/llm.ts b/src/llm.ts index f672756..ad339fe 100644 --- a/src/llm.ts +++ b/src/llm.ts @@ -75,7 +75,7 @@ export class OpenAIRAG implements LLM { new RAGApplicationBuilder() .setModel( new OpenAi({ - model: "gpt-4", + model: "gpt-3.5-turbo", }), ) .setEmbeddingModel( From 057a9ba926ae7cadc424bc1afb588f63d56c5dfe Mon Sep 17 00:00:00 2001 From: uu-z Date: Fri, 10 Jan 2025 16:01:23 +0800 Subject: [PATCH 4/4] clean up code --- src/SentientAI.ts | 6 +- src/index.ts | 9 +-- src/llm.ts | 1 - src/tools/newsapi.ts | 8 ++- src/tools/weatherapi.ts | 148 +++++++++++++++++----------------------- src/workflow.ts | 5 +- tests/server.test.ts | 2 +- 7 files changed, 78 insertions(+), 101 deletions(-) diff --git a/src/SentientAI.ts b/src/SentientAI.ts index 748f208..2468a67 100644 --- a/src/SentientAI.ts +++ b/src/SentientAI.ts @@ -8,12 +8,12 @@ import { export class SentientAI { weatherAgent = new Agent({ tools: [ - new CurrentWeatherAPITool(process.env.NUBILA_API_KEY!), - new ForecastWeatherAPITool(process.env.OPENWEATHER_API_KEY!), + new CurrentWeatherAPITool(), + new ForecastWeatherAPITool(), ], }); - newsTool = new NewsAPITool(process.env.NEWSAPI_API_KEY!); + newsTool = new NewsAPITool(); agent = new Agent({ tools: [this.weatherAgent, this.newsTool] }); } diff --git a/src/index.ts b/src/index.ts index 1d68539..f04db8c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,11 +33,6 @@ async function runExample() { return; } - const openWeatherApiKey = process.env.OPEN_WEATHER_API_KEY; - if (!openWeatherApiKey) { - console.error("Please set the OPEN_WEATHER_API_KEY environment variable."); - return; - } const newsApiKey = process.env.NEWSAPI_API_KEY; if (!newsApiKey) { @@ -47,8 +42,8 @@ async function runExample() { const weatherAgent = new Agent({ tools: [ - new CurrentWeatherAPITool(nubilaApiKey), - new ForecastWeatherAPITool(openWeatherApiKey), + new CurrentWeatherAPITool(), + new ForecastWeatherAPITool(), ], }); diff --git a/src/llm.ts b/src/llm.ts index ad339fe..bfa7856 100644 --- a/src/llm.ts +++ b/src/llm.ts @@ -84,7 +84,6 @@ export class OpenAIRAG implements LLM { }), ) .setVectorDatabase(new LibSqlDb({ path: "./data.db" })) - .setStore(new LibSqlStore({ path: "./data.db" })) .build() .then((rag) => (this.rag = rag)); } diff --git a/src/tools/newsapi.ts b/src/tools/newsapi.ts index 05cb2e6..8e7f3b6 100644 --- a/src/tools/newsapi.ts +++ b/src/tools/newsapi.ts @@ -8,8 +8,12 @@ interface NewsAPIResponse { } export class NewsAPITool extends APITool { - constructor(apiKey: string) { - super("NewsAPI", "Fetches today's headlines from News API", apiKey); + constructor() { + if (!process.env.NEWSAPI_API_KEY) { + console.error("Please set the NUBILA_API_KEY environment variable."); + return; + } + super("NewsAPI", "Fetches today's headlines from News API", process.env.NEWSAPI_API_KEY!); } async execute(input: string): Promise { diff --git a/src/tools/weatherapi.ts b/src/tools/weatherapi.ts index 667fe17..1a3ac3e 100644 --- a/src/tools/weatherapi.ts +++ b/src/tools/weatherapi.ts @@ -24,14 +24,17 @@ export class CurrentWeatherAPITool implements Tool { "Gets the current weather from Nubila API. Input is json with latitude and longitude to retrieve weather data."; twitterAccount: string = "nubilanetwork"; - private readonly apiKey: string; - private readonly baseUrl: string; + private apiKey: string = process.env.NUBILA_API_KEY! + private baseUrl: string = "https://api.nubila.ai/api/v1/weather" - constructor(apiKey: string) { - this.apiKey = apiKey; - this.baseUrl = "https://api.nubila.ai/api/v1/weather"; + constructor() { + if (!process.env.NUBILA_API_KEY) { + console.error("Please set the NUBILA_API_KEY environment variable."); + return; + } } + async execute(userInput: any): Promise { // check user input is json with latitude and longitude if ( @@ -88,104 +91,81 @@ export class CurrentWeatherAPITool implements Tool { } } -interface ForecastWeatherResponse { - cod: string; - message: number; - cnt: number; - list: Array<{ - dt: number; - main: { - temp: number; - feels_like: number; - temp_min: number; - temp_max: number; - pressure: number; - sea_level: number; - grnd_level: number; - humidity: number; - temp_kf: number; - }; - weather: Array<{ - id: number; - main: string; - description: string; - icon: string; - }>; - clouds: { - all: number; - }; - wind: { - speed: number; - deg: number; - }; - visibility: number; - pop: number; - rain?: { - "1h": number; - }; - sys: { - pod: string; - }; - dt_txt: string; - }>; - city: { - id: number; - name: string; - coord: { - lat: number; - lon: number; - }; - country: string; - population: number; - timezone: number; - sunrise: number; - sunset: number; - }; +interface NubilaForecastData { + dt: number; + temp: number; + feels_like: number; + humidity: number; + pressure: number; + wind_speed: number; + wind_direction: number; + condition: string; +} + +interface NubilaForecastResponse { + data: NubilaForecastData[]; + ok: boolean; } export class ForecastWeatherAPITool implements Tool { name: string = "ForecastWeatherAPITool"; description: string = - "Get weather forecast data from the OpenWeather API. Input is json with 'cityName' to retrieve weather data."; + "Get weather forecast data from the Nubila API. Input is json with latitude and longitude to retrieve weather data."; - private readonly apiKey: string; - private readonly baseUrl: string; - constructor(apiKey: string) { - this.apiKey = apiKey; - this.baseUrl = "https://api.openweathermap.org/data/2.5/forecast"; + private apiKey: string = process.env.NUBILA_API_KEY! + private baseUrl: string = "https://api.nubila.ai/api/v1/forecast" + + constructor() { + if (!process.env.NUBILA_API_KEY) { + console.error("Please set the NUBILA_API_KEY environment variable."); + return; + } } + async execute(userInput: any): Promise { if ( !userInput || typeof userInput !== "object" || - !("cityName" in userInput) + !("latitude" in userInput) || + !("longitude" in userInput) ) { - return "Invalid input. Please provide a JSON object with 'cityName' property."; + return "Invalid input. Please provide a JSON object with 'latitude' and 'longitude' properties."; } - const cityName = userInput.cityName; + + const url = `${this.baseUrl}?lat=${userInput.latitude}&lon=${userInput.longitude}`; + try { - const response = await fetch( - `${this.baseUrl}?q=${cityName}&appid=${this.apiKey}`, - ); - const data: ForecastWeatherResponse = await response.json(); - const weatherList = data?.list; - if ( - !weatherList || - !Array.isArray(weatherList) || - weatherList.length === 0 - ) { + const response = await fetch(url, { + headers: { + "x-api-key": this.apiKey, + }, + signal: AbortSignal.timeout(5000), + }); + + if (!response.ok) { + const errorMessage = `API request failed with status: ${response.status} ${response.statusText}`; + return `Weather API Error: ${errorMessage}`; + } + + const data: NubilaForecastResponse = await response.json(); + const forecastData = data.data; + + if (!forecastData || !Array.isArray(forecastData) || forecastData.length === 0) { return "No available weather data."; } - const summaries = weatherList.map((item) => { - const date = item.dt_txt; // Use dt_txt for the date - const temperature = (item.main.temp - 273.15).toFixed(2); // Convert Kelvin to Celsius - const weatherDescription = item.weather[0].description; // Weather description - const windSpeed = item.wind.speed; // Wind speed - return `On ${date}, the temperature is ${temperature}°C, the weather is ${weatherDescription}, and the wind speed is ${windSpeed} m/s.`; + + const summaries = forecastData.map((item) => { + const date = new Date(item.dt * 1000).toLocaleString(); + const temperature = item.temp; + const condition = item.condition; + const windSpeed = item.wind_speed; + return `On ${date}, the temperature is ${temperature}°C, the weather is ${condition}, and the wind speed is ${windSpeed} m/s.`; }); - return `Weather Forecast Data for ${cityName}: ` + summaries.join(" "); + + return `Weather Forecast Data for ${userInput.latitude}, ${userInput.longitude}: ` + summaries.join(" "); } catch (error) { + console.error("Error fetching forecast data:", error); return "Could not retrieve weather information. Please check the API or your network connection."; } } diff --git a/src/workflow.ts b/src/workflow.ts index 5fce103..0cd912d 100644 --- a/src/workflow.ts +++ b/src/workflow.ts @@ -18,7 +18,7 @@ export class Workflow { this.fastllm = new FastLLM(); } if (!this.llm) { - this.llm = new OpenAIRAG(); + this.llm = new OpenAILLM(); } } @@ -53,8 +53,6 @@ export class Workflow { if (action.tool) { const toolOutput = await action.tool.execute(action.output); - console.log("toolOutput:", toolOutput); - // FEED TOOL OUTPUT BACK TO LLM // Previous Conversation: ${JSON.stringify(this.memory.loadMemoryVariables().history)} const finalPrompt = this.agent.prompt({ @@ -64,6 +62,7 @@ export class Workflow { toolInput: action.output, }); output = await this.llm.generate(finalPrompt); + console.log({ output }) } else { output = action.output; // LLM handles it directly (no tool used) } diff --git a/tests/server.test.ts b/tests/server.test.ts index 693fb90..72b88c2 100644 --- a/tests/server.test.ts +++ b/tests/server.test.ts @@ -9,7 +9,7 @@ describe("Server", () => { vi.mock("../src/SentientAI", () => ({ SentientAI: vi.fn().mockImplementation(() => ({ agent: new (class { - async run(_: string): Promise { + async execute(_: string): Promise { return "mocked response"; } })(),