Skip to content

Commit

Permalink
refactor: rewrite underlying architecture of the framework to recursi…
Browse files Browse the repository at this point in the history
…ve object (#105)

Fixes #68 
Related #102 

There are a lot of changes in this PR, I will break them down here,
together with motivation.

The prime motivation for the change was to simplify the structure of
"state" by getting rid of agent specific properties (such as agentName,
agentRequest) and moving to a simple state object that can have "child"
states (either single element, or an array).

That way, we could get rid of special handling for supervisor, resource
planner (two built-in agents) and further simplify the logic.

Thanks to that, we have "out-of-the-box" support for parallelism,
cancellations, hand-offs. If agent wants to delegate, simply create new
`workflowState` and add it as a child, then return state (see how
"supervisor" is implemented). If agent wants to hand-off the task, they
can simply replace their entire state (see how "resourcePlanner" gets
its job done).

Other changes worth mentioning:
- Agent does not have role anymore. Now, what matters is the key on
"team" object. This is aligned with how we define tools. This will make
it better and more future proof if we serialize state object on the
server. We no longer rely on array positions.
- Renamed "members" array to "team" object
- Supervisor and Planner are now normal agents (and you can overwrite
them, or change their behavior, or define your own)
- Added tool helpers to be used on the server side

Here is screenshot of what the output looks like at the moment:


![3EB0FB32C3162E9A2F78_1](https://github.com/user-attachments/assets/b2e3b7b4-afea-436e-b6b2-73e6f7407c13)

---------

Co-authored-by: Piotr Karwatka <[email protected]>
  • Loading branch information
grabbou and pkarw authored Dec 12, 2024
1 parent 5886455 commit aab1c36
Show file tree
Hide file tree
Showing 33 changed files with 743 additions and 829 deletions.
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,16 @@ import { solution, workflow } from 'fabrice-ai/workflow'
import { lookupWikipedia } from './tools/wikipedia.js'

const activityPlanner = agent({
role: 'Activity Planner',
description: `You are skilled at creating personalized itineraries...`,
})

const landmarkScout = agent({
role: 'Landmark Scout',
description: `You research interesting landmarks...`,
tools: { lookupWikipedia },
})

const workflow = workflow({
members: [activityPlanner, landmarkScout],
team: { activityPlanner, landmarkScout },
description: `Plan a trip to Wrocław, Poland...`,
})

Expand Down Expand Up @@ -129,16 +127,15 @@ const state = await teamwork(workflow)

#### Server-side Teamwork

The server-side version of teamwork is perfectly suited for long-running workflows that require external tool execution or manual intervention. It will not wait for the tool to be executed, but will return the state of the workflow.
We provide a server-side version of `teamwork` that is perfectly suited for long-running workflows that require external tool execution or manual intervention. It will not wait for the tool to be executed, but will return the state of the workflow.

You can then handle tool calls on your own, and call `teamwork` again when ready.

```typescript
import { teamwork } from 'fabrice-ai/server'
import { teamwork } from 'fabrice-ai/teamwork'

// If status is `assigned`, you need to handle tool calls on your own.
// Otherwise, status is `finished` and you can read the result.
const nextState = await teamwork(workflow)
// Setting third argumenet to `false` will stop waiting for the tool to be executed.
const nextState = await teamwork(workflow, prevState, false)
```

This pattern is especially useful for:
Expand Down
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Researches and summarizes the top news from the past week into a comprehensive r

> `src/github_trending.ts`
Scrapes and analyzes trending Python projects from GitHub, creating a markdown summary report.
Scrapes and analyzes trending Typescript projects from GitHub, creating a markdown summary report.

**Actors:** Github Researcher, Redactor

Expand Down
7 changes: 3 additions & 4 deletions example/src/ecommerce_product_description.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { visionTool } from '@fabrice-ai/tools/vision'
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 { solution, workflow } from 'fabrice-ai/workflow'
import { workflow } from 'fabrice-ai/workflow'
import path from 'path'

const techExpert = agent({
role: 'Technical expert',
description: `
You are skilled at extracting and describing most detailed
technical information about the product from the photo.
Expand All @@ -17,7 +17,6 @@ const techExpert = agent({
})

const marketingManager = agent({
role: 'Marketing content writer',
description: `
You are skilled at writing catchy product descriptions
making customers to instantly fall in love with the product.
Expand All @@ -26,7 +25,7 @@ const marketingManager = agent({
})

const productDescriptionWorkflow = workflow({
members: [techExpert, marketingManager],
team: { techExpert, marketingManager },
description: `
Based on the picture '${path.resolve(import.meta.dirname, '../assets/example-sneakers.jpg')}' make the eCommerce product to
list this product on the website.
Expand Down
17 changes: 8 additions & 9 deletions example/src/github_trending.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { createFireCrawlTool } from '@fabrice-ai/tools/firecrawl'
import { getApiKey } from '@fabrice-ai/tools/utils'
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 { solution, workflow } from 'fabrice-ai/workflow'
import { workflow } from 'fabrice-ai/workflow'

const apiKey = await getApiKey('Firecrawl.dev API Key', 'FIRECRAWL_API_KEY')

Expand All @@ -12,7 +13,6 @@ const { firecrawl } = createFireCrawlTool({
})

const githubResearcher = agent({
role: 'Github Researcher',
description: `
You are skilled at browsing what's hot on Github trending page.
`,
Expand All @@ -22,25 +22,24 @@ const githubResearcher = agent({
})

const wrapupRedactor = agent({
role: 'Redactor',
description: `
Your role is to wrap up reports.
Your role is to compile and summarize information.
You're great at creating a wrap-up reports.
You're famous of beautiful Markdown formatting.
`,
})

const wrapUpTrending = workflow({
members: [githubResearcher, wrapupRedactor],
team: { githubResearcher, wrapupRedactor },
description: `
Research the URL "https://github.com/trending/python" page using scraper tool
Get 3 top projects. You can get the title and description from the project page.
Then summarize it all into a comprehensive report markdown output.
Research the URL "https://github.com/trending/typescript" page using firecrawl tool
Summarize information about 3 top projects into a comprehensive report markdown output.
Here are some ground rules to follow:
- Include one sentence summary for each project.
`,
output: `
Comprehensive markdown report with the top trending python projects.
Comprehensive markdown report with the top trending typescript projects.
`,
snapshot: logger,
})
Expand Down
48 changes: 19 additions & 29 deletions example/src/github_trending_vector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,28 @@ 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 { solution } from 'fabrice-ai/solution'
import { teamwork } from 'fabrice-ai/teamwork'
import { logger } from 'fabrice-ai/telemetry'
import { tool } from 'fabrice-ai/tool'
import { solution, workflow } from 'fabrice-ai/workflow'
import { workflow } from 'fabrice-ai/workflow'
import { z } from 'zod'

import { askUser } from './tools/askUser.js'

const apiKey = await getApiKey('Firecrawl.dev API Key', 'FIRECRAWL_API_KEY')

const printTool = tool({
description: 'Display information to the user',
parameters: z.object({
message: z.string().describe('The information to be displayed'),
}),
execute: async ({ message }) => {
console.log(message)
return ''
},
})

const { saveDocumentInVectorStore, searchInVectorStore } = createVectorStoreTools()

const { firecrawl } = createFireCrawlTool({
apiKey,
})

const githubResearcher = agent({
role: 'Github Researcher',
description: `
You are skilled at browsing what's hot on Github trending page.
You are saving the documents to vector store for later usage
You are skilled at browsing Github 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,
Expand All @@ -42,38 +32,38 @@ const githubResearcher = agent({
})

const wrapupRedactor = agent({
role: 'Redactor',
description: `
Your role is to wrap up reports.
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: {
printTool,
askUser,
searchInVectorStore,
},
})

const wrapUpTrending = workflow({
members: [githubResearcher, wrapupRedactor],
team: { githubResearcher, wrapupRedactor },
description: `
Research the URL "https://github.com/trending/typescript" page using scraper tool
Get 3 top projects. You can get the title and description from the project page.
Then summarize it all into a comprehensive report markdown output.
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.
Ask user about which project he wants to learn more.
Search for the project in the vector store and provide more details in the report.
reate a comprehensive report markdown output:
- 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:
- Include one sentence summary for each project.
- Print the list of projects to the user.
- Ask user about which project he wants to learn more.
- Display more information about this specific project from the vector store.
- 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 with the top trending Typescript projects.
Detailed report about the project selected by the user.
Comprehensive markdown report including:
- summary on top trending Typescript projects.
- detailed info about the project selected by the user.
`,
snapshot: logger,
})
Expand Down
7 changes: 3 additions & 4 deletions example/src/library_photo_to_website.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { createFileSystemTools } from '@fabrice-ai/tools/filesystem'
import { visionTool } from '@fabrice-ai/tools/vision'
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 { solution, workflow } from 'fabrice-ai/workflow'
import { workflow } from 'fabrice-ai/workflow'
import path from 'path'

const workingDir = path.resolve(import.meta.dirname, '../assets/')
Expand All @@ -13,7 +14,6 @@ const { saveFile, readFile, listFilesFromDirectory } = createFileSystemTools({
})

const librarian = agent({
role: 'Librarian',
description: `
You are skilled at scanning and identifying books in the library.
When asked, you will analyze the photo of the library and list all the books that you see, in details.
Expand All @@ -24,7 +24,6 @@ const librarian = agent({
})

const webmaster = agent({
role: 'HTML Webmaster',
description: `
You are skilled at creating HTML pages.
You are good at using templates for creating HTML pages.
Expand All @@ -41,7 +40,7 @@ const imagePath = path.join(workingDir, 'photo-library.jpg')
const outputPath = path.join(workingDir, 'library.html')

const bookLibraryWorkflow = workflow({
members: [librarian, webmaster],
team: { librarian, webmaster },
description: `
Analyze the photo of the library and list all the books in the library.
Generate a website that lists all the books in the library.
Expand Down
2 changes: 1 addition & 1 deletion example/src/medical_survey.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { solution } from 'fabrice-ai/solution'
import { teamwork } from 'fabrice-ai/teamwork'
import { solution } from 'fabrice-ai/workflow'

import { preVisitNoteWorkflow } from './medical_survey/workflow.js'

Expand Down
5 changes: 1 addition & 4 deletions example/src/medical_survey/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { workflow } from 'fabrice-ai/workflow'

import { askUser } from '../tools/askUser.js'


const nurse = agent({
role: 'Nurse',
description: `
You are skille nurse / doctor assistant.
You role is to cooperate with reporter to create a pre-visit note for a patient that is about to come for a visit.
Expand All @@ -18,7 +16,6 @@ const nurse = agent({
})

const reporter = agent({
role: 'Reporter',
description: `
You are skilled at preparing great looking reports.
You can prepare a report for a patient that is about to come for a visit.
Expand All @@ -27,7 +24,7 @@ const reporter = agent({
})

export const preVisitNoteWorkflow = workflow({
members: [nurse, reporter],
team: { nurse, reporter },
description: `
Create a pre-visit note for a patient that is about to come for a visit.
The note should include the patient's health and symptoms.
Expand Down
Loading

0 comments on commit aab1c36

Please sign in to comment.