Skip to content

Commit

Permalink
Merge pull request #170 from NimbleBoxAI/fury
Browse files Browse the repository at this point in the history
CF-1.6.2
  • Loading branch information
yashbonde authored Nov 3, 2023
2 parents 2a8cc5d + 2d503ec commit af12f5d
Show file tree
Hide file tree
Showing 46 changed files with 837 additions and 1,690 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ jobs:
python -m pip install sphinx-rtd-theme==1.2.2
cd server
python3 -m pip install .
cd ..
python3 scripts/list_builtins.py ./api_docs/templates/components-list.rst ./api_docs/examples/components-list.rst
- name: Build docs
run: |
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,5 @@ private.sh
api_docs/_build/
api_docs/_static/
cf
locust_file.py
demo/
demo/
logs.py
7 changes: 0 additions & 7 deletions api_docs/cf_server/chainfury_server.api.fury.rst

This file was deleted.

1 change: 0 additions & 1 deletion api_docs/cf_server/chainfury_server.api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ Submodules
:maxdepth: 4

chainfury_server.api.chains
chainfury_server.api.fury
chainfury_server.api.prompts
chainfury_server.api.user
2 changes: 1 addition & 1 deletion api_docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
project = "ChainFury"
copyright = "2023, NimbleBox Engineering"
author = "NimbleBox Engineering"
release = "1.6.0"
release = "1.6.2"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
56 changes: 56 additions & 0 deletions api_docs/examples/agent-theory.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Fury Agents Manifesto
=====================

**Starting date: 21st October, 2023**


ChainFury's `first commit`_ was on 7th April, 2023. It has been about 6 months since then and it has undergone lot of
production usage. With multiple API changes and engines, we are now at a stable place. This is also a good time to check
up on the things that have released in the wild till now.

tl;dr
-----

Predictable automated chains as agents, that use tree searching algorithms to find solution to a problem with given set
of actions. Has ability to create new actions and learn from feedback.

Agents
------

There have been several "agent like" systems that have been released. Some can create code, others can perform advanced
searching. Ultimately all of them can be modelled as a Chain and use different algorithms. ``chainfury`` can support
all algorithms and has a type-based robust chaining engine. This means building agents is the next logical step. There
is a lot of theory and academic research done on the topic of agents. All of them have different tradeoffs. But first
let's start with the requirements of an agent.

* Agent should be able to execute task without human intervention
* Agent should stop when it can't proceed
* Agent should be interruptible to take in feedback
* Agent should take inputs from it's environment
* Agent should be able to remember things over time
* Agent should be predictable in its behaviour, debuggable

Von-Neumann machine
~~~~~~~~~~~~~~~~~~~

We are followers of the agent as a `Von-Neumann machine`_, which means each chain has a complete I/O mechanism where
each input and output can be accessed independently. ``chainfury`` can use different memory systems like VectorDB, etc.
meaning that it can persist data over time. For the CPU analogy we have :py:mod:`chainfury.base.Chain` which models the
execution as a DAG of :py:class:`chainfury.base.Node` objects. Each node contains the unit step of the chain. We can
parallellise and speed up executions by using :py:mod:`chainfury.utils.threaded_map`.

``chainfury`` is already being used in production and thus with the infrastructure layer sorted we can then think about
what to build on top of it.

Automated
~~~~~~~~~

One of the most important things is that these agents be automated and run without human in the loop.

Edits
-----

.. all the links here
.. _first commit: https://github.com/NimbleBoxAI/ChainFury/commit/64a5f7b0fcf3d8bcce0cde6ee974b659ebe01b68
.. _Von-Neumann machine: https://blog.nimblebox.ai/new-flow-engine-from-scratch
75 changes: 75 additions & 0 deletions api_docs/examples/components-list.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
Components List
===============

.. this is a jinja template document, run scripts/list_builtins.py to generate components-list.rst
There are several components that are shipped with the ``chainfury``. You can find how to access the underlying function
via the `components page`_.

.. code-block::python
# load the registries you can do these imports
from chainfury import programatic_actions_registry, ai_actions_registry
Programatic Actions
-------------------

Programatic means that these are generally not an LLM call rather something more standard like calling an API,
transforming the data, etc.


* `serper-api` - Search the web with Serper. Copy: ``programatic_actions_registry.get("serper-api")``

* `call_api_requests` - Call an API using the requests library. Copy: ``programatic_actions_registry.get("call_api_requests")``

* `regex_search` - Perform a regex search on the text and get items in an array. Copy: ``programatic_actions_registry.get("regex_search")``

* `regex_substitute` - Perform a regex substitution on the text and get the result. Copy: ``programatic_actions_registry.get("regex_substitute")``

* `json_translator` - Extract a value from a JSON object using a list of keys. Copy: ``programatic_actions_registry.get("json_translator")``


AI Action Components
--------------------

These actions generally take the input, create a custom prompt, call the Model and respond back with the result.


* `hello-world` - Python function loaded from a file used as an AI action. Copy: ``ai_actions_registry.get("hello-world")``

* `deep-rap-quote` - J-type action will write a deep poem in the style of a character. Copy: ``ai_actions_registry.get("deep-rap-quote")``


Memory Components
-----------------

Memory components are used to store data, which can be a Vector DB or Redis, etc.


* `qdrant-write` - Write to the Qdrant DB using the Qdrant client. Copy: ``memory_registry.get_write("qdrant-write")``

* `qdrant-read` - Function to read from the Qdrant DB using the Qdrant client. Copy: ``memory_registry.get_read("qdrant-read")``


Model Components
----------------

Model are the different GenAI models that can be used from the ``chainfury``.


* `stability-text-to-image` - Generate a new image from a text prompt. Copy: ``model_registry.get("stability-text-to-image")``

* `chatnbx` - Chat with the ChatNBX API with OpenAI compatability, see more at https://chat.nbox.ai/. Copy: ``model_registry.get("chatnbx")``

* `nbx-deploy` - Call NimbleBox LLMOps deploy API. Copy: ``model_registry.get("nbx-deploy")``

* `openai-completion` - Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. Copy: ``model_registry.get("openai-completion")``

* `openai-chat` - Given a list of messages describing a conversation, the model will return a response. Copy: ``model_registry.get("openai-chat")``

* `openai-embedding` - Given a list of messages create embeddings for each message. Copy: ``model_registry.get("openai-embedding")``


.. all the links are here
.. _components page: https://qdrant.tech/documentation/tutorials/bulk-upload/#upload-directly-to-disk
4 changes: 2 additions & 2 deletions api_docs/examples/qa-rag.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Question Answering using ChainFury
==================================
(RAG) Q/A with ChainFury
========================

One of the first use cases of LLM powered apps is question answering. This is how you should think about this problem:

Expand Down
8 changes: 7 additions & 1 deletion api_docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ Read the latest blog posts:

examples/install
examples/storing-private-data
examples/use-chainfury-privately

.. toctree::
:maxdepth: 2
Expand All @@ -65,6 +64,13 @@ Read the latest blog posts:
:caption: Integrations

source/chainfury.components
examples/components-list

.. toctree::
:maxdepth: 2
:caption: Research

examples/agent-theory

.. toctree::
:maxdepth: 2
Expand Down
54 changes: 54 additions & 0 deletions api_docs/templates/components-list.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Components List
===============

.. this is a jinja template document, run scripts/list_builtins.py to generate components-list.rst
There are several components that are shipped with the ``chainfury``. You can find how to access the underlying function
via the `components page`_.

.. code-block::python
# load the registries you can do these imports
from chainfury import programatic_actions_registry, ai_actions_registry
Programatic Actions
-------------------

Programatic means that these are generally not an LLM call rather something more standard like calling an API,
transforming the data, etc.

{% for component in pc %}
* `{{ component.id }}` - {{ component.description }}
{% endfor %}

AI Action Components
--------------------

These actions generally take the input, create a custom prompt, call the Model and respond back with the result.

{% for component in ac %}
* `{{ component.id }}` - {{ component.description }}
{% endfor %}

Memory Components
-----------------

Memory components are used to store data, which can be a Vector DB or Redis, etc.

{% for component in mc %}
* `{{ component.id }}` - {{ component.description }}
{% endfor %}

Model Components
----------------

Model are the different GenAI models that can be used from the ``chainfury``.

{% for component in moc %}
* `{{ component.id }}` - {{ component.description }}
{% endfor %}

.. all the links are here
.. _components page: https://qdrant.tech/documentation/tutorials/bulk-upload/#upload-directly-to-disk

2 changes: 1 addition & 1 deletion cf_internal
17 changes: 15 additions & 2 deletions chainfury/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,21 @@
if os.path.exists(_dotenv_fp):
dotenv.load_dotenv(_dotenv_fp)

from chainfury.utils import exponential_backoff, UnAuthException, DoNotRetryException, logger, CFEnv
from chainfury.utils import (
exponential_backoff,
UnAuthException,
DoNotRetryException,
logger,
CFEnv,
)
from chainfury.base import Var, Node, Secret, Chain, Model, Edge
from chainfury.agent import model_registry, programatic_actions_registry, ai_actions_registry, memory_registry, AIAction, Memory
from chainfury.agent import (
model_registry,
programatic_actions_registry,
ai_actions_registry,
memory_registry,
AIAction,
Memory,
)
from chainfury.client import get_client
from chainfury import components
6 changes: 5 additions & 1 deletion chainfury/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Node,
Model,
Var,
Chain,
)

# Models
Expand Down Expand Up @@ -170,6 +171,9 @@ def register(
Returns:
Node: Node
"""
if len(node_id) > 80:
raise ValueError(f"Node id '{node_id}' is too long, max length is 80")

logger.debug(f"Registering p-node '{node_id}'")
if node_id in self.nodes:
raise Exception(f"Node '{node_id}' already registered")
Expand Down Expand Up @@ -692,7 +696,7 @@ def __call__(self, **data: Dict[str, Any]) -> Any:

class MemoryRegistry:
def __init__(self) -> None:
self._memories = {}
self._memories: Dict[str, Node] = {}

def register_write(
self,
Expand Down
2 changes: 1 addition & 1 deletion chainfury/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ def __init__(
collection_name: str,
id: str,
fn: object,
description,
description: str = "",
usage: List[Union[str, int]] = [],
tags=[],
):
Expand Down
12 changes: 7 additions & 5 deletions chainfury/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
from functools import lru_cache
from typing import Dict, Any, Tuple

from chainfury.utils import logger
from chainfury.utils import logger, CFEnv


class Subway:
"""
Simple code that allows writing APIs by `.attr.ing` them. This is inspired from gRPC style functional calls which
hides the complexity of underlying networking. This is useful when you are trying to debug live server directly.
**If you want to setup a client, use the ``get_client`` function, this is not what you are looking for.**
Note:
User is solely responsible for checking if the certain API endpoint exists or not. This simply wraps the API
calls and does not do any validation.
Expand Down Expand Up @@ -140,8 +142,8 @@ def get_client(prefix: str = "/api/", url="", token: str = "", trailing: str = "
Example:
>>> from chainfury import get_client
>>> client = get_client()
>>> cf_actions = client.api.v1.fury.actions.list()
>>> cf_actions
>>> chains = client.api.chains() # GET /api/chains
>>> chains
Note:
The `get_client` function is a convenience function that can be used to get a client object. It is not required
Expand All @@ -158,10 +160,10 @@ def get_client(prefix: str = "/api/", url="", token: str = "", trailing: str = "
Returns:
Subway: A Subway object that can be used to interact with the API.
"""
url = url or os.environ.get("CF_URL", "")
url = url or CFEnv.CF_URL()
if not url:
raise ValueError("No url provided, please set CF_URL environment variable or pass url as argument")
token = token or os.environ.get("CF_TOKEN", "")
token = token or CFEnv.CF_TOKEN()
if not token:
raise ValueError("No token provided, please set CF_TOKEN environment variable or pass token as argument")

Expand Down
Loading

0 comments on commit af12f5d

Please sign in to comment.