From 900a84240032885089ede0032006f07fb181d94c Mon Sep 17 00:00:00 2001 From: Piotr Karwatka Date: Thu, 12 Dec 2024 18:04:21 +0100 Subject: [PATCH 1/3] fix: final fixes on github_trending_vector - simplifying the workflow + dividing it to more self-explanatory agent roles for making resourcePlanner life easier --- example/src/github_trending_vector.ts | 36 ++++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/example/src/github_trending_vector.ts b/example/src/github_trending_vector.ts index 8bd01ff..1040235 100644 --- a/example/src/github_trending_vector.ts +++ b/example/src/github_trending_vector.ts @@ -5,9 +5,7 @@ import { agent } from 'fabrice-ai/agent' import { solution } from 'fabrice-ai/solution' import { teamwork } from 'fabrice-ai/teamwork' import { logger } from 'fabrice-ai/telemetry' -import { tool } from 'fabrice-ai/tool' import { workflow } from 'fabrice-ai/workflow' -import { z } from 'zod' import { askUser } from './tools/askUser.js' @@ -19,11 +17,10 @@ const { firecrawl } = createFireCrawlTool({ apiKey, }) -const githubResearcher = agent({ +const webCrawler = agent({ description: ` - You are skilled at browsing Github pages. + You are skilled at browsing Web pages. You are saving the documents to vector store for later usage. - You don't do any other thing just these two tasks. `, tools: { firecrawl, @@ -31,34 +28,43 @@ const githubResearcher = agent({ }, }) -const wrapupRedactor = agent({ +const topicSelector = agent({ + description: ` + You ask users for the topic specified in the task. + `, + tools: { + askUser, + }, +}) + +const reportCompiler = agent({ description: ` You ask users for which topic to focus on if it's defined in the task. Then - you search relevant information in Vector Store and compile reports based on it. You're famous of beautiful Markdown formatting. `, tools: { - askUser, searchInVectorStore, }, }) const wrapUpTrending = workflow({ - team: { githubResearcher, wrapupRedactor }, + team: { webCrawler, topicSelector, reportCompiler }, description: ` - Research the URL "https://github.com/trending/typescript" page using firecrawl tool - Select 3 top projects. Browse for details about these projects on their subpages. - Save it all to the vector store. + Research the URL "https://github.com/trending/typescript" page. + Select 3 top projects. Browse details about these projects on their subpages. + Store each page in Vector Store for further usage. + After you store the information you don't need to browse the page again + because everything is stored in Vector Store. + + Ask user about which project he wants to learn more. Ask user only once. - Ask user about which project he wants to learn more. - reate a comprehensive report markdown output: + Create a comprehensive markdown report using information from Vector Store, based on user selection: - create a one, two sentence summary about every project. - include detailed summary about the project selected by the user. Here are some ground rules to follow: - - Browser the pages onle once and store content in Vector Store. - Use Vector Store if you need information about the project. - - Before making up the record: ask user about which project he wants to learn more. `, output: ` Comprehensive markdown report including: From c6844195aa92a539d1d06441e4979eb58bda2a01 Mon Sep 17 00:00:00 2001 From: Piotr Karwatka Date: Thu, 12 Dec 2024 18:29:50 +0100 Subject: [PATCH 2/3] fix: CR fixes --- example/src/github_trending_vector.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/example/src/github_trending_vector.ts b/example/src/github_trending_vector.ts index 1040235..e16ffd8 100644 --- a/example/src/github_trending_vector.ts +++ b/example/src/github_trending_vector.ts @@ -28,9 +28,9 @@ const webCrawler = agent({ }, }) -const topicSelector = agent({ +const human = agent({ description: ` - You ask users for the topic specified in the task. + You can ask user and get their answer to questions that are needed by other agents. `, tools: { askUser, @@ -39,8 +39,8 @@ const topicSelector = agent({ const reportCompiler = agent({ description: ` - You ask users for which topic to focus on if it's defined in the task. - Then - you search relevant information in Vector Store and compile reports based on it. + You can search Vector Store to find relevant informations and create reports based on it + Based on the information from Vector Store you can compile a comprehensive report. You're famous of beautiful Markdown formatting. `, tools: { @@ -49,7 +49,7 @@ const reportCompiler = agent({ }) const wrapUpTrending = workflow({ - team: { webCrawler, topicSelector, reportCompiler }, + team: { webCrawler, human, reportCompiler }, description: ` Research the URL "https://github.com/trending/typescript" page. Select 3 top projects. Browse details about these projects on their subpages. From 09e025ea6fe71983a7933fed7032c77d255e0def Mon Sep 17 00:00:00 2001 From: Piotr Karwatka Date: Thu, 12 Dec 2024 18:54:33 +0100 Subject: [PATCH 3/3] feat: this is just a POC for showing how to replace the supervisor to a custom one - planing the execution plan ahead --- example/src/agents/static_supervisor.ts | 110 ++++++++++++++++++++++++ example/src/github_trending_vector.ts | 4 +- 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 example/src/agents/static_supervisor.ts diff --git a/example/src/agents/static_supervisor.ts b/example/src/agents/static_supervisor.ts new file mode 100644 index 0000000..85e97fc --- /dev/null +++ b/example/src/agents/static_supervisor.ts @@ -0,0 +1,110 @@ +import s from 'dedent' +import { agent, AgentOptions } from 'fabrice-ai/agent' +import { childState } from 'fabrice-ai/state' +import { tool } from 'fabrice-ai/tool' +import { zodResponseFormat } from 'openai/helpers/zod' +import { z } from 'zod' + +const defaults: AgentOptions = { + tools: { + printThePlan: tool({ + description: 'Tool for printing a message to the user', + parameters: z.object({ + message: z.string().describe('The message to print to the user'), + }), + execute: ({ message }) => { + console.log(message) + return Promise.resolve('User got the message') + }, + }), + }, + run: async (state, context, workflow) => { + const response = await workflow.team[state.agent].provider.completions({ + messages: [ + { + role: 'system', + content: s` + You are a planner that breaks down complex workflows into smaller, actionable steps. + Your job is to determine the execution plan of the workflow. + Print the plan using the 'printThePlan' tool. + Then return the tasks one by one untill execution plan end. + Take available agents into consideration. + If all required tasks are completed, return null. + + Rules: + 1. Each task should be self-contained and achievable + 2. Tasks should be specific and actionable + 3. Return null when the workflow is complete + 4. Consider dependencies and order of operations + 5. Use context from completed tasks to inform next steps + + Here are the available agents: + + ${Object.entries(workflow.team).map(([name, agent]) => + agent.description ? `${agent.description}` : '' + )} + + `, + }, + { + role: 'assistant', + content: 'What is the request?', + }, + ...context, + ...state.messages, + ], + temperature: 0.2, + response_format: zodResponseFormat( + z.object({ + plan: z.array(z.string()).describe('The execution plan of the workflow'), + task: z + .string() + .describe('The next task to be completed or null if the workflow is complete') + .nullable(), + reasoning: z + .string() + .describe('The reasoning for selecting the next task or why the workflow is complete'), + }), + 'next_task' + ), + }) + + try { + const content = response.choices[0].message.parsed + console.log(content) + if (!content) { + throw new Error('No content in response') + } + + if (!content.task) { + return { + ...state, + status: 'finished', + } + } + + const agentRequest = { + role: 'user' as const, + content: content.task, + } + + return { + ...state, + status: 'running', + messages: [...state.messages, agentRequest], + child: childState({ + agent: 'resourcePlanner', + messages: [agentRequest], + }), + } + } catch (error) { + throw new Error('Failed to determine next task') + } + }, +} + +export const staticSupervisor = (options?: AgentOptions) => + agent({ + ...defaults, + ...options, + }) diff --git a/example/src/github_trending_vector.ts b/example/src/github_trending_vector.ts index e16ffd8..f849407 100644 --- a/example/src/github_trending_vector.ts +++ b/example/src/github_trending_vector.ts @@ -2,11 +2,13 @@ import { createFireCrawlTool } from '@fabrice-ai/tools/firecrawl' import { getApiKey } from '@fabrice-ai/tools/utils' import { createVectorStoreTools } from '@fabrice-ai/tools/vector' import { agent } from 'fabrice-ai/agent' +import { supervisor } from 'fabrice-ai/agents/supervisor' import { solution } from 'fabrice-ai/solution' import { teamwork } from 'fabrice-ai/teamwork' import { logger } from 'fabrice-ai/telemetry' import { workflow } from 'fabrice-ai/workflow' +import { staticSupervisor } from './agents/static_supervisor.js' import { askUser } from './tools/askUser.js' const apiKey = await getApiKey('Firecrawl.dev API Key', 'FIRECRAWL_API_KEY') @@ -49,7 +51,7 @@ const reportCompiler = agent({ }) const wrapUpTrending = workflow({ - team: { webCrawler, human, reportCompiler }, + team: { webCrawler, human, reportCompiler, supervisor: staticSupervisor() }, // an example of overriding supervisor description: ` Research the URL "https://github.com/trending/typescript" page. Select 3 top projects. Browse details about these projects on their subpages.