{"id":23479564,"url":"https://github.com/callstackincubator/fabrice-ai","last_synced_at":"2025-05-16T13:08:24.183Z","repository":{"id":267465038,"uuid":"899447701","full_name":"callstackincubator/fabrice-ai","owner":"callstackincubator","description":"A lightweight, functional, and composable framework for building AI agents. No PhD required.","archived":false,"fork":false,"pushed_at":"2024-12-30T13:38:45.000Z","size":3119,"stargazers_count":278,"open_issues_count":54,"forks_count":17,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-22T23:36:53.984Z","etag":null,"topics":["agents","ai","ai-agents-framework","framework","llm","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/callstackincubator.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-06T09:36:53.000Z","updated_at":"2025-04-18T10:54:15.000Z","dependencies_parsed_at":"2024-12-24T19:31:56.198Z","dependency_job_id":"3cd0478b-15d9-4732-bb92-eeb743ccc1a2","html_url":"https://github.com/callstackincubator/fabrice-ai","commit_stats":null,"previous_names":["callstackincubator/fabrice-ai","callstackincubator/ai-agent-framework"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callstackincubator%2Ffabrice-ai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callstackincubator%2Ffabrice-ai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callstackincubator%2Ffabrice-ai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callstackincubator%2Ffabrice-ai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/callstackincubator","download_url":"https://codeload.github.com/callstackincubator/fabrice-ai/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254535828,"owners_count":22087399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","ai","ai-agents-framework","framework","llm","typescript"],"created_at":"2024-12-24T19:31:41.042Z","updated_at":"2025-05-16T13:08:24.159Z","avatar_url":"https://github.com/callstackincubator.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/bd03d003-9c22-4154-8953-519a5faabaa6\" height=\"250\" /\u003e\n\u003c/p\u003e\n\nA lightweight, functional, and composable framework for building AI agents that work together to solve complex tasks. \n\nBuilt with TypeScript and designed to be serverless-ready.\n\n## Table of Contents\n\n- [Getting Started](#getting-started)\n  - [Using create-fabrice-ai](#using-create-fabrice-ai)\n  - [Manual Installation](#manual-installation) \n- [Why Another AI Agent Framework?](#why-another-ai-agent-framework)\n- [Core Concepts](#core-concepts)\n  - [Easy to create and compose](#easy-to-create-and-compose)\n  - [Infrastructure-agnostic](#infrastructure-agnostic)\n  - [Stateless](#stateless)\n  - [Batteries included](#batteries-included)\n- [Agents](#agents)\n  - [Creating Custom Agents](#creating-custom-agents)\n  - [Built-in Agents](#built-in-agents)\n  - [Replacing Built-in Agents](#replacing-built-in-agents)\n- [Workflows](#workflows)\n- [Workflow States](#workflow-states)\n  - [Root State](#root-state) \n  - [Child State](#child-state)\n  - [Delegating Tasks](#delegating-tasks)\n  - [Handing off Tasks](#handing-off-tasks)\n- [Providers](#providers)\n  - [Built-in Providers](#built-in-providers)\n  - [Using Different Providers](#using-different-providers)\n  - [Creating Custom Providers](#creating-custom-providers)\n- [Tools](#tools)\n  - [Built-in Tools](#built-in-tools)\n  - [Creating Custom Tools](#creating-custom-tools)\n  - [Using Tools](#using-tools)\n- [Execution](#execution)\n  - [Completing the workflow](#completing-the-workflow)\n  - [Long-running operations](#long-running-operations)\n  - [Custom execution](#custom-execution)\n- [Test framework](./packages/bdd/README.md)\n- [Contributors](#contributors)\n- [Made with ❤️ at Callstack](#made-with-❤️-at-callstack)\n\n## Getting Started\n\nIt is very easy to get started. All you have to do is to create a file with your agents and workflow, then run it.\n\n### Using `npx create-fabrice-ai`\n\nUse our creator tool to quickly create a new AI agent project.\n\n```bash\nnpx create-fabrice-ai\n```\n\nYou can choose from a few templates. You can see a full list of them [here](./example/README.md).\n\n### Manually\n\n```bash\nnpm install fabrice-ai\n```\n\n#### Create your first workflow\n\nHere is a simple example of a workflow that researches and plans a trip to Wrocław, Poland:\n\n```ts\nimport { agent } from 'fabrice-ai/agent'\nimport { teamwork } from 'fabrice-ai/teamwork'\nimport { solution, workflow } from 'fabrice-ai/workflow'\n\nimport { lookupWikipedia } from './tools/wikipedia.js'\n\nconst activityPlanner = agent({\n  description: `You are skilled at creating personalized itineraries...`,\n})\n\nconst landmarkScout = agent({\n  description: `You research interesting landmarks...`,\n  tools: { lookupWikipedia },\n})\n\nconst workflow = workflow({\n  team: { activityPlanner, landmarkScout },\n  description: `Plan a trip to Wrocław, Poland...`,\n})\n\nconst result = await teamwork(workflow)\nconsole.log(solution(result))\n```\n\n#### Running the example\n\nFinally, you can run the example by simply executing the file.\n\n**Using `bun`**\n\n```bash\nbun your_file.ts\n```\n\n**Using `node`**\n\n```bash\nnode --import=tsx your_file.ts\n```\n\n## Why Another AI Agent Framework?\n\nMost existing AI agent frameworks are either too complex, heavily object-oriented, or tightly coupled to specific infrastructure. \n\nWe wanted something different - a framework that embraces functional programming principles, remains stateless, and stays laser-focused on composability.\n\n**Now, English + Typescript is your tech stack.**\n\n## Core Concepts\n\nHere are the core concepts of Fabrice:\n\n### Easy to create and compose\n\nTeamwork should be easy and fun, just like in real life. It should not require you to learn a new framework and mental model to put your AI team together.\n\n### Infrastructure-agnostic\n\nThere should be no assumptions about the infrastructure you're using. You should be able to use any provider and any tools, in any environment.\n\n### Stateless\n\nNo classes, no side effects. Every operation should be a function that returns a new state.\n\n### Batteries included\n\nWe should provide you with all tools and features needed to build your AI team, locally and in the cloud.\n\n## Agents\n\nAgents are specialized workers with specific roles and capabilities. Agents can call available tools and complete assigned tasks. Depending on the task complexity, it can be done in a single step, or multiple steps.\n\n### Creating Custom Agents\n\nTo create a custom agent, you can use our `agent` helper function or implement the `Agent` interface manually.\n\n```ts\nimport { agent } from 'fabrice-ai/agent'\n\nconst myAgent = agent({\n  role: '\u003c\u003c your role \u003e\u003e',\n  description: '\u003c\u003c your description \u003e\u003e',\n})\n```\n\nAdditionally, you can give it access to tools by passing a `tools` property to the agent. You can learn more about tools [here](#tools). You can also set custom `provider` for each agent. You can learn more about providers [here](#providers).\n\n### Built-in Agents\n\nFabrice comes with a few built-in agents that help it run your workflows out of the box.\n\nSupervisor, `supervisor`, is responsible for coordinating the workflow. \nIt splits your workflow into smaller, more manageable parts, and coordinates the execution.\n\nResource Planner, `resourcePlanner`, is responsible for assigning tasks to available agents, based on their capabilities.\n\nFinal Boss, `finalBoss`, is responsible for wrapping up the workflow and providing a final output,\nin case total number of iterations exeeceds available threshold.\n\n### Replacing Built-in Agents\n\nYou can overwrite built-in agents by setting it in the workflow.\n\nFor example, to replace built-in `supervisor` agent, you can do it like this:\n\n```ts\nimport { supervisor } from './my-supervisor.js'\n\nworkflow({\n  team: { supervisor },\n})\n```\n\n## Workflows\n\nWorkflows define how agents collaborate to achieve a goal. They specify:\n- Team members\n- Task description\n- Expected output\n- Optional configuration\n\n## Workflow State\n\nWorkflow state is a representation of the current state of the workflow. It is a tree of states, where each state represents a single agent's work. \n\nAt each level, we have the following properties:\n- `agent`: name of the agent that is working on the task\n- `status`: status of the agent\n- `messages`: message history\n- `children`: child states\n\nFirst element of the `messages` array is always a request to the agent, typically a user message. Everything that follows is a message history, including all the messages exchanged with the provider.\n\nWorkflow can have multiple states:\n- `idle`: no work has been started yet\n- `running`: work is in progress\n- `paused`: work is paused and there are tools that must be called to resume\n- `finished`: work is complete\n- `failed`: work has failed due to an error\n\n### Initial State\n\nWhen you run `teamwork(workflow)`, initial state is automatically created for you by calling `rootState(workflow)` behind the scenes. \n\n\u003e [!NOTE]\n\u003e You can also provide your own initial state (for example, to resume a workflow from a previous state). You can learn more about it in the [server-side usage](#server-side-usage) section.\n\n### Root State\n\nRoot state is a special state that contains an initial request based on the workflow and points to the `supervisor` agent, which is responsible for splitting the work into smaller, more manageable parts. \n\nYou can learn more about the `supervisor` agent [here](#built-in-agents).\n\n### Child State\n\nChild state is like root state, but it points to any agent, such as one from your team. \n\nYou can create it manually, or use `childState` function.\n\n```ts\nconst child = childState({\n  agent: '\u003c\u003c agent name \u003e\u003e',\n  messages: user('\u003c\u003c task description \u003e\u003e'),\n})\n```\n\n\u003e [!TIP]\n\u003e Fabrice exposes a few helpers to facilitate creating messages, such as `user` and `assistant`. You can use them to create messages in a more readable way, although it is not required.\n\n### Delegating Tasks\n\nTo delegate the task, just add a new child state to your agent's state.\n\n```ts\nconst state = {\n  ...state,\n  children: [\n    ...state.children,\n    childState({\n      /** agent to work on the task */\n      agent: '\u003c\u003c agent name \u003e\u003e',\n      /** task description */\n      messages: [\n        {\n          role: 'user',\n          content: '\u003c\u003c task description \u003e\u003e',\n        }\n      ],\n    })\n  ]\n}\n```\n\nTo make it easier, you can use `delegate` function to delegate the task.\n\n```ts\nconst state = delegate(state, [agent, '\u003c\u003c task description \u003e\u003e'])\n```\n\n### Handing off Tasks\n\nTo hand off the task, you can replace your agent's state with a new state, that points to a different agent.\n\n```ts\nconst state = childState({\n  agent: '\u003c\u003c new agent name \u003e\u003e',\n  messages: state.messages,\n})\n```\n\nIn the example above, we're passing the entire message history to the new agent, including the original request and all the work done by any previous agent. It is up to you to decide how much of the history to pass to the new agent.\n\n## Providers\n\nProviders are responsible for sending requests to the LLM and handling the responses.\n\n### Built-in Providers\n\nFabrice comes with a few built-in providers:\n- OpenAI (structured output)\n- OpenAI (using tools as response format)\n- Groq\n\nYou can learn more about them [here](./packages/framework/src/providers/README.md).\n\nIf you're working with an OpenAI compatible provider, you can use the `openai` provider with a different base URL and API key, such as:\n\n```ts\nopenai({\n  model: '\u003c\u003c your model \u003e\u003e',\n  options: {\n    apiKey: '\u003c\u003c your_api_key \u003e\u003e',\n    baseURL: '\u003c\u003c your_base_url \u003e\u003e',\n  },\n})\n```\n\n### Using Different Providers\n\nBy default, Fabrice uses OpenAI gpt-4o model. You can change the default model or provider either for the entire system, or for specific agent.\n\nTo do it for the entire workflow:\n```ts\nimport { grok } from 'fabrice-ai/providers/grok'\n\nworkflow({\n  /** other options go here */\n  provider: grok()\n})\n```\n\nTo change it for specific agent:\n\n```ts\nimport { grok } from 'fabrice-ai/providers/grok'\n\nagent({\n  /** other options go here */\n  provider: grok()\n})\n```\n\nNote that an agent's provider always takes precedence over a workflow's provider. Tools always receive the provider from the agent that triggered their execution.\n\n### Creating Custom Providers\n\nTo create a custom provider, you need to implement the `Provider` interface. \n\n```ts\nconst myProvider = (options: ProviderOptions): Provider =\u003e {\n  return {\n    chat: async () =\u003e {\n      /** your implementation goes here */\n    },\n  }\n}\n```\n\nYou can learn more about the `Provider` interface [here](./packages/framework/src/models.ts).\n\n## Tools\n\nTools extend agent capabilities by providing concrete actions they can perform.\n\n### Built-in Tools\n\nFabrice comes with a few built-in tools via `@fabrice-ai/tools` package. For most up-to-date list, please refer to the [README](./packages/tools/README.md).\n\n### Creating Custom Tools\n\nTo create a custom tool, you can use our `tool` helper function or implement the `Tool` interface manually.\n\n```ts\nimport { tool } from 'fabrice-ai/tools'\n\nconst myTool = tool({\n  description: 'My tool description',\n  parameters: z.object({\n    /** your Zod schema goes here */\n  }),\n  execute: async (parameters, context) =\u003e {\n    /** your implementation goes here */\n  },\n})\n```\n\nTools will use the same provider as the agent that triggered them. Additionally, you can access the `context` object, which gives you access to the provider, as well as current message history.\n\n### Using Tools\n\nTo give an agent access to a tool, you need to add it to the agent's `tools` property.\n\n```ts\nagent({\n  role: '\u003c\u003c your role \u003e\u003e',\n  tools: { searchWikipedia },\n})\n```\n\nSince tools are passed to an LLM and referred by their key, you should use meaningful names for them, for increased effectiveness.\n\n## Execution\n\nExecution is the process of running the workflow to completion. A completed workflow is a workflow with state \"finished\" at its root. \n\n### Completing the workflow\n\nThe easiest way to complete the workflow is to call `teamwork(workflow)` function. It will run the workflow to completion and return the final state.\n\n```ts\nconst state = await teamwork(workflow)\nconsole.log(solution(state))\n```\n\nCalling `solution(state)` will return the final output of the workflow, which is its last message.\n\n### Long-running operations\n\nIf you are running workflows in the cloud, or any other environment where you want to handle tool execution manually, you can call teamwork the following way:\n\n```ts\n/** read state from the cache */\n\n/** run the workflow */\nconst state = await teamwork(workflow, prevState, false)\n\n/** save state to the cache */\n```\n\nPassing second argument to `teamwork` is optional. If you don't provide it, root state will be created automatically. Otherwise, it will be used as a starting point for the next iteration.\n\nLast argument is a boolean flag that determines if tools should be executed. If you set it to `false`, you are responsible for calling tools manually. Teamwork will stop iterating over the workflow and return the current state with `paused` status.\n\n### Custom execution\n\nIf you want to handle tool execution manually, you can use `iterate` function to build up your own recursive iteration logic over the workflow state.\n\nHave a look at how `teamwork` is implemented [here](./packages/framework/src/teamwork.ts) to understand how it works.\n\n\n### BDD Testing\n\nThere's a packaged called `fabrice-ai/bdd` dedicated to unit testing - actually to Behavioral Driven Development. [Check the docs](./packages/bdd/README.md).\n\n## Contributors\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/grabbou\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/2464966?v=4?s=100\" width=\"100px;\" alt=\"Mike\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMike\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#code-grabbou\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://catchthetornado.com\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/211899?v=4?s=100\" width=\"100px;\" alt=\"Piotr Karwatka\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePiotr Karwatka\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#code-pkarw\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\n## Made with ❤️ at Callstack\n\nFabrice is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Callstack](https://callstack.com) is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi!\n\nLike the project? ⚛️ [Join the team](https://callstack.com/careers/?utm_campaign=Senior_RN\u0026utm_source=github\u0026utm_medium=readme) who does amazing stuff for clients and drives React Native Open Source! 🔥 \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcallstackincubator%2Ffabrice-ai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcallstackincubator%2Ffabrice-ai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcallstackincubator%2Ffabrice-ai/lists"}