acte


Nameacte JSON
Version 0.0.15 PyPI version JSON
download
home_pageNone
SummaryA framework to build Tools for AI Agents, a GUI-like solution to enhance Function Calling.
upload_time2024-10-21 06:49:49
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseMIT
keywords ai agent tool framework llm function calling
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![logo.png](https://github.com/j66n/acte/raw/master/images/logo.png)

![Example.gif](https://github.com/j66n/acte/raw/master/images/Example.gif)

## What is Acte?

Acte is a framework to build GUI-like tools for AI Agents.

### Why GUI-like?

The current tool solution, as known as Function Calling, is based on API calling, like weather API, Google API, etc. It
has two main problems in complex scenarios:

1. Multiple APIs increase the cognitive load for AI Agents, potentially leading to reasoning errors, especially when the
   APIs have a strict calling order.
2. Directly calling APIs is a way with too much freedom degrees, lacking constraints, potentially resulting in data
   errors.

The way Agents interact with APIs reminds me of how human interacts with computers in old days. A guy faces a black and
thick screen and types the keyboard, while looking up commands in a manual. Not just Agent, we also faces these two
problems.

Then a technique that surprised Steve Jobs comes up: Graphical User Interface (GUI).

Since then, most of us no longer directly interact with command lines (a kind of API). We interact with API through GUI.
GUI generally solved these two problems by constraining interaction to reduce cognitive load and degrees of freedom.

This is why Agents also need GUI-like tools. I prefer calling it Agentic User Interface (AUI).

## Quick Start

### **Installation**

```shell
pip install acte
```

### Example1: Hello World

```python
from acte import Component, v
from acte.chatbot import OpenaiChatbot
from acte.server import Server
from acte.session import SessionManager


class HelloWorld(Component):
    def view(self) -> None:
        v.text("Hello World")


server = Server(
    session_manager=SessionManager(HelloWorld, debug=True),
    chatbot=OpenaiChatbot(  # default model is gpt-4o
        api_key="YOUR OPENAI API KEY",
    )
)

if __name__ == '__main__':
    server.run()
```

1. Copy the code to a Python file, and set **OpenAI Api Key**.

2. Run the code, and visit the playground: http://127.0.0.1:8000.
   ![Example_00_00_hello_world.png](https://github.com/j66n/acte/raw/master/images/Example_00_00_hello_world.png)

3. Input "Hi, please new a session, and tell what you see."
   Then, the Agent will interact with **Screen**, and give you a response.
   ![Example_00_01_hello_world.png](https://github.com/j66n/acte/raw/master/images/Example_00_01_hello_world.png)

Note: You can also interact with **Screen** to debug your app.

---

### Example2: Counter

```python
from acte import Component, v
from acte.chatbot import OpenaiChatbot
from acte.server import Server
from acte.session import SessionManager
from acte.state.signal import Signal


class Counter(Component):
    def __init__(self) -> None:
        self._n = Signal(0)

    def view(self) -> None:
        v.text("This is a counter.")

        with v.div():
            v.text(lambda: f"Current Value: {self._n.value}")
            # _n is Signal, so you need to use self._n.value in lambda

        v.button("add", on_press=self._add)

    async def _add(self) -> None:
        await self._n.set(self._n.value + 1)


server = Server(
    session_manager=SessionManager(Counter, debug=True),
    chatbot=OpenaiChatbot(
        api_key="YOUR OPENAI API KEY",
    )
)

if __name__ == '__main__':
    server.run()
```

1. Agent can **press** the button in **Screen**. The number on the right-top of the button is **Interactive ID**.
   Agent interacts with **Screen** by pointing to ID.
   ![Example_01_00_counter.png](https://github.com/j66n/acte/raw/master/images/Example_01_00_counter.png)

2. Interaction's result will show in **Screen**. You can click "View"s in **Dialog** to check the **Screen** status in
   each step.
   ![Example_01_01_counter.png](https://github.com/j66n/acte/raw/master/images/Example_01_01_counter.png)

---

### Example3: Restaurant Assistant

```python
from typing import Callable, Awaitable

from acte.chatbot import OpenaiChatbot
from acte.schema import IntSchema
from acte.server import Server
from acte.session import SessionManager

from acte import Component, v, Prop, as_prop
from acte.state.signal import Signal


class MenuItem(Component):
   def __init__(
           self,
           name: Prop[str],  # Prop = Ref[T] | T
           price: Prop[float],
           quantity: Prop[int],
           on_quantity_change: Callable[[str, float, int], Awaitable[None]]
   ) -> None:
      self._name = as_prop(name)  # as_prop is to convert T to Ref[T]
      self._price = as_prop(price)
      self._quantity = as_prop(quantity)

      self._on_quantity_change = on_quantity_change

   def view(self) -> None:
      with v.div():
         v.text(lambda: f"{self._name.value}: ${self._price.value}")
         v.input("quantity", self._quantity, self._on_set, schema=IntSchema())

   async def _on_set(self, value: str) -> None:
      await self._on_quantity_change(
         self._name.value,
         self._price.value,
         0 if value == '' else int(value)
      )


class Menu(Component):
   def __init__(self) -> None:
      self._menu = {
         "Pizza": {"price": 10.0, "quantity": Signal(0)},  # Signal is a kind of Ref, but can be set
         "Coke": {"price": 2.0, "quantity": Signal(0)},
      }

   def view(self) -> None:
      v.text("Super Restaurant Menu")

      for key, value in self._menu.items():
         v.component(
            MenuItem(
               name=key,
               price=value['price'],
               quantity=value['quantity'],
               on_quantity_change=self._on_quantity_change,
            )
         )

      v.text(self.total)

      v.button("checkout", on_press=self._checkout)

   def total(self) -> str:
      total = 0

      for key, value in self._menu.items():
         total += value['price'] * value['quantity'].value

      return f"Total: ${total}"

   async def _on_quantity_change(self, name: str, price: float, quantity: int) -> None:
      await self._menu[name]['quantity'].set(quantity)

   async def _checkout(self) -> None:
      total = self.total()

      for value in self._menu.values():
         await value['quantity'].set(0)

      print(f"Checkout: {total}")


server = Server(
   session_manager=SessionManager(Menu, debug=True),
   chatbot=OpenaiChatbot(
      system_message="You are restaurant assistant to help customers to order food through App. "
                     "You should confirm before Checkout",
      api_key="YOUR OPENAI API KEY",
   )
)

if __name__ == '__main__':
   server.run()

```

1. Agent can **fill** input fields in **Screen**.
   ![Example_02_00_restaurant_assistant.png](https://github.com/j66n/acte/raw/master/images/Example_02_00_restaurant_assistant.png)

2. Input fields also have their own **Interactive ID**. Agent can take multiple actions in one calling.
   ![Example_02_01_restaurant_assistant.png](https://github.com/j66n/acte/raw/master/images/Example_02_01_restaurant_assistant.png)

3. You can define the backend logic after Agent press the button, such as make a request.
   ![Example_02_02_restaurant_assistant.png](https://github.com/j66n/acte/raw/master/images/Example_02_02_restaurant_assistant.png)

## Tool API

Acte Tool has 3 APIs: `new_session`, `execute`, and `display`,
which can be accessed by HTTP request or `SessionManager`

### 1. New Session

Start a new App session, then display the session's latest screen.

#### HTTP request

```http request
POST /session
```

#### SessionManager

```python
from acte.session import SessionManager

sm = SessionManager(...)

sm.new_session()
```

#### Return

```
{
    "session_id": str,
    "screen": str,
}
```

---

### 2. Execute

Execute one or more action(s), then display the session's latest screen.

#### HTTP Request

```http request
POST /execute

json:
{
    "session_id": "str",
    "actions": [
        {
            "target_id": "str",
            "action_type": "str",
            "value": "str | None",
        },
    ]
}
```

#### SessionManager

```python
from acte.session import SessionManager

sm = SessionManager(...)

sm.execute(
    {
        "session_id": str,
        "actions": [
            {
                "target_id": str,  # interactive id
                "action_type": str,  # one of ["press", "fill"]
                "value": str | None,  # required when action_type is "fill"
            },
            ...
        ]
    }
)
```

#### Return

```python
{
    "session_id": str,
    "screen": str,
}
```

---

### 3. Display

Display the session's latest screen.

#### HTTP Request

```http request
POST /display

json: 
{
    "session_id": "str",
}
```

#### SessionManager

```python
from acte.session import SessionManager

sm = SessionManager(...)

sm.execute(
    {
        "session_id": str,
    }
)
```

#### Return

```python
{
    "session_id": str,
    "screen": str,
}
```

## Roadmap

- [ ] Full Document

- [ ] Test Code

Note: The project is in Alpha stage. The API may change frequently.

## LICENSE

The project is licensed under the terms of the MIT license.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "acte",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "ai, agent, tool, framework, llm, function calling",
    "author": null,
    "author_email": "j66n <jonathan.nuance@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/56/09/a75122e91cfea0e88b367843ff3bd38b93b8b306e98724d1a74e72dabc84/acte-0.0.15.tar.gz",
    "platform": null,
    "description": "![logo.png](https://github.com/j66n/acte/raw/master/images/logo.png)\n\n![Example.gif](https://github.com/j66n/acte/raw/master/images/Example.gif)\n\n## What is Acte?\n\nActe is a framework to build GUI-like tools for AI Agents.\n\n### Why GUI-like?\n\nThe current tool solution, as known as Function Calling, is based on API calling, like weather API, Google API, etc. It\nhas two main problems in complex scenarios:\n\n1. Multiple APIs increase the cognitive load for AI Agents, potentially leading to reasoning errors, especially when the\n   APIs have a strict calling order.\n2. Directly calling APIs is a way with too much freedom degrees, lacking constraints, potentially resulting in data\n   errors.\n\nThe way Agents interact with APIs reminds me of how human interacts with computers in old days. A guy faces a black and\nthick screen and types the keyboard, while looking up commands in a manual. Not just Agent, we also faces these two\nproblems.\n\nThen a technique that surprised Steve Jobs comes up: Graphical User Interface (GUI).\n\nSince then, most of us no longer directly interact with command lines (a kind of API). We interact with API through GUI.\nGUI generally solved these two problems by constraining interaction to reduce cognitive load and degrees of freedom.\n\nThis is why Agents also need GUI-like tools. I prefer calling it Agentic User Interface (AUI).\n\n## Quick Start\n\n### **Installation**\n\n```shell\npip install acte\n```\n\n### Example1: Hello World\n\n```python\nfrom acte import Component, v\nfrom acte.chatbot import OpenaiChatbot\nfrom acte.server import Server\nfrom acte.session import SessionManager\n\n\nclass HelloWorld(Component):\n    def view(self) -> None:\n        v.text(\"Hello World\")\n\n\nserver = Server(\n    session_manager=SessionManager(HelloWorld, debug=True),\n    chatbot=OpenaiChatbot(  # default model is gpt-4o\n        api_key=\"YOUR OPENAI API KEY\",\n    )\n)\n\nif __name__ == '__main__':\n    server.run()\n```\n\n1. Copy the code to a Python file, and set **OpenAI Api Key**.\n\n2. Run the code, and visit the playground: http://127.0.0.1:8000.\n   ![Example_00_00_hello_world.png](https://github.com/j66n/acte/raw/master/images/Example_00_00_hello_world.png)\n\n3. Input \"Hi, please new a session, and tell what you see.\"\n   Then, the Agent will interact with **Screen**, and give you a response.\n   ![Example_00_01_hello_world.png](https://github.com/j66n/acte/raw/master/images/Example_00_01_hello_world.png)\n\nNote: You can also interact with **Screen** to debug your app.\n\n---\n\n### Example2: Counter\n\n```python\nfrom acte import Component, v\nfrom acte.chatbot import OpenaiChatbot\nfrom acte.server import Server\nfrom acte.session import SessionManager\nfrom acte.state.signal import Signal\n\n\nclass Counter(Component):\n    def __init__(self) -> None:\n        self._n = Signal(0)\n\n    def view(self) -> None:\n        v.text(\"This is a counter.\")\n\n        with v.div():\n            v.text(lambda: f\"Current Value: {self._n.value}\")\n            # _n is Signal, so you need to use self._n.value in lambda\n\n        v.button(\"add\", on_press=self._add)\n\n    async def _add(self) -> None:\n        await self._n.set(self._n.value + 1)\n\n\nserver = Server(\n    session_manager=SessionManager(Counter, debug=True),\n    chatbot=OpenaiChatbot(\n        api_key=\"YOUR OPENAI API KEY\",\n    )\n)\n\nif __name__ == '__main__':\n    server.run()\n```\n\n1. Agent can **press** the button in **Screen**. The number on the right-top of the button is **Interactive ID**.\n   Agent interacts with **Screen** by pointing to ID.\n   ![Example_01_00_counter.png](https://github.com/j66n/acte/raw/master/images/Example_01_00_counter.png)\n\n2. Interaction's result will show in **Screen**. You can click \"View\"s in **Dialog** to check the **Screen** status in\n   each step.\n   ![Example_01_01_counter.png](https://github.com/j66n/acte/raw/master/images/Example_01_01_counter.png)\n\n---\n\n### Example3: Restaurant Assistant\n\n```python\nfrom typing import Callable, Awaitable\n\nfrom acte.chatbot import OpenaiChatbot\nfrom acte.schema import IntSchema\nfrom acte.server import Server\nfrom acte.session import SessionManager\n\nfrom acte import Component, v, Prop, as_prop\nfrom acte.state.signal import Signal\n\n\nclass MenuItem(Component):\n   def __init__(\n           self,\n           name: Prop[str],  # Prop = Ref[T] | T\n           price: Prop[float],\n           quantity: Prop[int],\n           on_quantity_change: Callable[[str, float, int], Awaitable[None]]\n   ) -> None:\n      self._name = as_prop(name)  # as_prop is to convert T to Ref[T]\n      self._price = as_prop(price)\n      self._quantity = as_prop(quantity)\n\n      self._on_quantity_change = on_quantity_change\n\n   def view(self) -> None:\n      with v.div():\n         v.text(lambda: f\"{self._name.value}: ${self._price.value}\")\n         v.input(\"quantity\", self._quantity, self._on_set, schema=IntSchema())\n\n   async def _on_set(self, value: str) -> None:\n      await self._on_quantity_change(\n         self._name.value,\n         self._price.value,\n         0 if value == '' else int(value)\n      )\n\n\nclass Menu(Component):\n   def __init__(self) -> None:\n      self._menu = {\n         \"Pizza\": {\"price\": 10.0, \"quantity\": Signal(0)},  # Signal is a kind of Ref, but can be set\n         \"Coke\": {\"price\": 2.0, \"quantity\": Signal(0)},\n      }\n\n   def view(self) -> None:\n      v.text(\"Super Restaurant Menu\")\n\n      for key, value in self._menu.items():\n         v.component(\n            MenuItem(\n               name=key,\n               price=value['price'],\n               quantity=value['quantity'],\n               on_quantity_change=self._on_quantity_change,\n            )\n         )\n\n      v.text(self.total)\n\n      v.button(\"checkout\", on_press=self._checkout)\n\n   def total(self) -> str:\n      total = 0\n\n      for key, value in self._menu.items():\n         total += value['price'] * value['quantity'].value\n\n      return f\"Total: ${total}\"\n\n   async def _on_quantity_change(self, name: str, price: float, quantity: int) -> None:\n      await self._menu[name]['quantity'].set(quantity)\n\n   async def _checkout(self) -> None:\n      total = self.total()\n\n      for value in self._menu.values():\n         await value['quantity'].set(0)\n\n      print(f\"Checkout: {total}\")\n\n\nserver = Server(\n   session_manager=SessionManager(Menu, debug=True),\n   chatbot=OpenaiChatbot(\n      system_message=\"You are restaurant assistant to help customers to order food through App. \"\n                     \"You should confirm before Checkout\",\n      api_key=\"YOUR OPENAI API KEY\",\n   )\n)\n\nif __name__ == '__main__':\n   server.run()\n\n```\n\n1. Agent can **fill** input fields in **Screen**.\n   ![Example_02_00_restaurant_assistant.png](https://github.com/j66n/acte/raw/master/images/Example_02_00_restaurant_assistant.png)\n\n2. Input fields also have their own **Interactive ID**. Agent can take multiple actions in one calling.\n   ![Example_02_01_restaurant_assistant.png](https://github.com/j66n/acte/raw/master/images/Example_02_01_restaurant_assistant.png)\n\n3. You can define the backend logic after Agent press the button, such as make a request.\n   ![Example_02_02_restaurant_assistant.png](https://github.com/j66n/acte/raw/master/images/Example_02_02_restaurant_assistant.png)\n\n## Tool API\n\nActe Tool has 3 APIs: `new_session`, `execute`, and `display`,\nwhich can be accessed by HTTP request or `SessionManager`\n\n### 1. New Session\n\nStart a new App session, then display the session's latest screen.\n\n#### HTTP request\n\n```http request\nPOST /session\n```\n\n#### SessionManager\n\n```python\nfrom acte.session import SessionManager\n\nsm = SessionManager(...)\n\nsm.new_session()\n```\n\n#### Return\n\n```\n{\n    \"session_id\": str,\n    \"screen\": str,\n}\n```\n\n---\n\n### 2. Execute\n\nExecute one or more action(s), then display the session's latest screen.\n\n#### HTTP Request\n\n```http request\nPOST /execute\n\njson:\n{\n    \"session_id\": \"str\",\n    \"actions\": [\n        {\n            \"target_id\": \"str\",\n            \"action_type\": \"str\",\n            \"value\": \"str | None\",\n        },\n    ]\n}\n```\n\n#### SessionManager\n\n```python\nfrom acte.session import SessionManager\n\nsm = SessionManager(...)\n\nsm.execute(\n    {\n        \"session_id\": str,\n        \"actions\": [\n            {\n                \"target_id\": str,  # interactive id\n                \"action_type\": str,  # one of [\"press\", \"fill\"]\n                \"value\": str | None,  # required when action_type is \"fill\"\n            },\n            ...\n        ]\n    }\n)\n```\n\n#### Return\n\n```python\n{\n    \"session_id\": str,\n    \"screen\": str,\n}\n```\n\n---\n\n### 3. Display\n\nDisplay the session's latest screen.\n\n#### HTTP Request\n\n```http request\nPOST /display\n\njson: \n{\n    \"session_id\": \"str\",\n}\n```\n\n#### SessionManager\n\n```python\nfrom acte.session import SessionManager\n\nsm = SessionManager(...)\n\nsm.execute(\n    {\n        \"session_id\": str,\n    }\n)\n```\n\n#### Return\n\n```python\n{\n    \"session_id\": str,\n    \"screen\": str,\n}\n```\n\n## Roadmap\n\n- [ ] Full Document\n\n- [ ] Test Code\n\nNote: The project is in Alpha stage. The API may change frequently.\n\n## LICENSE\n\nThe project is licensed under the terms of the MIT license.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A framework to build Tools for AI Agents, a GUI-like solution to enhance Function Calling.",
    "version": "0.0.15",
    "project_urls": {
        "Homepage": "https://github.com/acte-all/acte"
    },
    "split_keywords": [
        "ai",
        " agent",
        " tool",
        " framework",
        " llm",
        " function calling"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "093c9ed1d950194dfd6aee929a3c794f208fe7c29ee105dbaedd112e16b7e658",
                "md5": "d465d30a306a9b1a5c3f09ee019aaefb",
                "sha256": "c442d155e6252ae50129512324de07c58fcf79ca467db56cc5eb11238e50951e"
            },
            "downloads": -1,
            "filename": "acte-0.0.15-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "d465d30a306a9b1a5c3f09ee019aaefb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 56999,
            "upload_time": "2024-10-21T06:49:47",
            "upload_time_iso_8601": "2024-10-21T06:49:47.489252Z",
            "url": "https://files.pythonhosted.org/packages/09/3c/9ed1d950194dfd6aee929a3c794f208fe7c29ee105dbaedd112e16b7e658/acte-0.0.15-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "5609a75122e91cfea0e88b367843ff3bd38b93b8b306e98724d1a74e72dabc84",
                "md5": "25e7d0287f8de8a94808e64901103dd6",
                "sha256": "d42246a22c73930e96e4f476e6785903c16c28ed2b447d8498ec8887dcb5a6fa"
            },
            "downloads": -1,
            "filename": "acte-0.0.15.tar.gz",
            "has_sig": false,
            "md5_digest": "25e7d0287f8de8a94808e64901103dd6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 38044,
            "upload_time": "2024-10-21T06:49:49",
            "upload_time_iso_8601": "2024-10-21T06:49:49.708652Z",
            "url": "https://files.pythonhosted.org/packages/56/09/a75122e91cfea0e88b367843ff3bd38b93b8b306e98724d1a74e72dabc84/acte-0.0.15.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-21 06:49:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "acte-all",
    "github_project": "acte",
    "github_not_found": true,
    "lcname": "acte"
}
        
Elapsed time: 2.43186s