Skip to content

Commit

Permalink
Liqun/plugin only 2 (microsoft#102)
Browse files Browse the repository at this point in the history
1. add documents
2. refine code for plugin-only mode
  • Loading branch information
liqul authored Jan 5, 2024
1 parent 956fd70 commit 07d6e4a
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from typing import List, Tuple
from typing import List, Optional, Tuple

from injector import inject

Expand Down Expand Up @@ -80,7 +80,13 @@ def select_plugins_for_prompt(

return self.selected_plugin_pool.get_plugins()

def reply(self, memory: Memory, event_handler: callable) -> Post:
def reply(
self,
memory: Memory,
event_handler,
prompt_log_path: Optional[str] = None,
use_back_up_engine: bool = False,
) -> Post:
# extract all rounds from memory
rounds = memory.get_role_rounds(
role="CodeInterpreter",
Expand All @@ -99,6 +105,10 @@ def reply(self, memory: Memory, event_handler: callable) -> Post:
rounds=rounds,
plugin_pool=self.plugin_pool,
)

if prompt_log_path is not None:
self.logger.dump_log_file({"prompt": prompt, "tools": tools}, prompt_log_path)

post = Post.create(message=None, send_from="CodeInterpreter", send_to="Planner")

llm_response = self.llm_api.chat_completion(
Expand Down
2 changes: 2 additions & 0 deletions taskweaver/code_interpreter/code_interpreter_plugin_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def reply(
response: Post = self.generator.reply(
memory,
event_handler,
prompt_log_path,
use_back_up_engine,
)

if response.message is not None:
Expand Down
10 changes: 9 additions & 1 deletion taskweaver/role/role.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
from typing import Optional

from taskweaver.memory import Memory, Post


class Role:
def reply(self, memory: Memory, event_handler: callable) -> Post:
def reply(
self,
memory: Memory,
event_handler,
prompt_log_path: Optional[str] = None,
use_back_up_engine: bool = False,
) -> Post:
pass
6 changes: 3 additions & 3 deletions website/docs/configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ The following table lists the parameters in the configuration file:
| `llm.api_version` | The version of the OpenAI API. | `2023-07-01-preview` |
| `llm.response_format` | The response format of the OpenAI API, could be `json_object`, `text` or `null`. | `json_object` |
| `code_interpreter.code_verification_on` | Whether to enable code verification. | `false` |
| `code_interpreter.plugin_only` | Whether to turn on the plugin only mode. | `false` |
| `code_interpreter.allowed_modules` | The list of allowed modules to import in code generation. | `"pandas", "matplotlib", "numpy", "sklearn", "scipy", "seaborn", "datetime", "typing"` |
| `logging.log_file` | The name of the log file. | `taskweaver.log` |
| `logging.log_folder` | The folder to store the log file. | `logs` |
Expand All @@ -29,8 +28,9 @@ The following table lists the parameters in the configuration file:
| `code_generator.auto_plugin_selection_topk` | The number of auto selected plugins in each round. | `3` |
| `session.max_internal_chat_round_num` | The maximum number of internal chat rounds between Planner and Code Interpreter. | `10` |
| `session.code_interpreter_only` | Allow users to directly communicate with the Code Interpreter. | `false` |
|`round_compressor.rounds_to_compress` | The number of rounds to compress. | `2` |
|`round_compressor.rounds_to_retain` | The number of rounds to retain. | `3` |
| `session.plugin_only` | Whether to turn on the plugin only mode. | `false` |
| `round_compressor.rounds_to_compress` | The number of rounds to compress. | `2` |
| `round_compressor.rounds_to_retain` | The number of rounds to retain. | `3` |


> 💡 $\{AppBaseDir\} is the project directory.
Expand Down
203 changes: 203 additions & 0 deletions website/docs/customization/plugin/how_to_develop_a_new_plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
---
id: develop_plugin
description: How to develop a new plugin
slug: /plugin/how_to_develop_a_new_plugin
---
# How to develop a new plugin

In this tutorial, we will introduce how to develop a strawman plugin in TaskWeaver. This plugin can render a input text in ascii art.

## Implement the python code

Create a python file named `ascii_render.py` in the `plugins` folder. The file name should be the same as the plugin name. The plugin name is defined in the plugin schema. In this example, the plugin name is `ascii_render`.
The following code is the template of the plugin implementation.
```python
from taskweaver.plugin import Plugin, register_plugin

@register_plugin
class PluginTemplate(Plugin):
def __call__(self, *args, **kwargs):
"""Implementation Starts"""
result, description = YourImplementation()
"""Implementation Ends"""

# if your want to add artifact from the execution result, uncomment the following code
# self.ctx.add_artifact(
# name="artifact",
# file_name="artifact.csv",
# type="df",
# val=result,
# )
return result, description
```

The typical way of implementing the plugin is to change the code between `Implementation Starts` and `Implementation Ends`. Note that the return are two variables _result_ and _description_. The _result_ stores whatever output required for follow-up processing (e.g., a DataFrame). The _description_ is a string to describe the result.

Let's make some changes to the code and the result is as follows:

```python
from taskweaver.plugin import Plugin, register_plugin

@register_plugin
class AsciiRenderPlugin(Plugin):
def __call__(self, text: str):
import pyfiglet
ascii_art_str = pyfiglet.figlet_format(text, font='isometric1')
return ascii_art_str
```
Note that this function depends on the package `pyfiglet`, so we need to install it with `pip install pyfiglet`.

## Configure the schema

Next, we need to configure the schema so that the LLM can understand the function
of the plugin. In the schema, there are several fields that should be filled,
including `name`, `enabled`, `required`, `description`, `parameters` and `returns`.
Please check [Plugin Introduction](https://microsoft.github.io/TaskWeaver/docs/plugin/plugin_intro)
for more details.
Create a yaml file named `ascii_render.yaml` and copy the following content into it.

```yaml
name: ascii_render
enabled: true
required: true
description: >-
This plugin renders the input text into ASCII art form.
The input should be a string and the output is also a string in ASCII art.
For example, result = ascii_render(text='Hello World').
parameters:
- name: text
type: str
required: true
description: >-
This is the input text to be rendered into ASCII art form.
returns:
- name: result
type: str
description: >-
The rendered text in ASCII art.
```
## Call the plugin
After the plugin is implemented and configured, we can call the plugin in the conversation.
The full conversation is as follows:
```bash
=========================================================
_____ _ _ __
|_ _|_ _ ___| | _ | | / /__ ____ __ _____ _____
| |/ _` / __| |/ /| | /| / / _ \/ __ `/ | / / _ \/ ___/
| | (_| \__ \ < | |/ |/ / __/ /_/ /| |/ / __/ /
|_|\__,_|___/_|\_\|__/|__/\___/\__,_/ |___/\___/_/
=========================================================
TaskWeaver: I am TaskWeaver, an AI assistant. To get started, could you please enter your request?
Human: render ABC in ascii art
>>> [INIT_PLAN]
1. Render the text 'ABC' into ASCII art
>>> [PLAN]
1. Instruct CodeInterpreter to render the text 'ABC' into ASCII art
>>> [CURRENT_PLAN_STEP]
1. Instruct CodeInterpreter to render the text 'ABC' into ASCII art
>>> [SEND_TO]
CodeInterpreter
>>> [MESSAGE]
Please render the text 'ABC' into ASCII art
>>> [PLANNER->CODEINTERPRETER]
Please render the text 'ABC' into ASCII art
>>> [PYTHON]
# Call the plugin function to render the text 'ABC' into ASCII art
ascii_art_result = ascii_render("ABC")
ascii_art_result
>>> [VERIFICATION]
NONE
>>> [STATUS]
SUCCESS
>>> [RESULT]
The execution of the generated python code above has succeeded

The result of above Python code after execution is:
___ ___ ___
/\ \ /\ \ /\ \
/::\ \ /::\ \ /::\ \
/:/\:\ \ /:/\:\ \ /:/\:\ \
/::\~\:\ \ /::\~\:\__\ /:/ \:\ \
/:/\:\ \:\__\ /:/\:\ \:|__| /:/__/ \:\__\
\/__\:\/:/ / \:\~\:\/:/ / \:\ \ \/__/
\::/ / \:\ \::/ / \:\ \
/:/ / \:\/:/ / \:\ \
/:/ / \::/__/ \:\__\
\/__/ ~~ \/__/

>>> [CODEINTERPRETER->PLANNER]
The following python code has been executed:

# Call the plugin function to render the text 'ABC' into ASCII art
ascii_art_result = ascii_render("ABC")
ascii_art_result



The execution of the generated python code above has succeeded

The result of above Python code after execution is:
___ ___ ___
/\ \ /\ \ /\ \
/::\ \ /::\ \ /::\ \
/:/\:\ \ /:/\:\ \ /:/\:\ \
/::\~\:\ \ /::\~\:\__\ /:/ \:\ \
/:/\:\ \:\__\ /:/\:\ \:|__| /:/__/ \:\__\
\/__\:\/:/ / \:\~\:\/:/ / \:\ \ \/__/
\::/ / \:\ \::/ / \:\ \
/:/ / \:\/:/ / \:\ \
/:/ / \::/__/ \:\__\
\/__/ ~~ \/__/

>>> [INIT_PLAN]
1. Render the text 'ABC' into ASCII art
>>> [PLAN]
1. Instruct CodeInterpreter to render the text 'ABC' into ASCII art
>>> [CURRENT_PLAN_STEP]
Report the ASCII art to the user
>>> [SEND_TO]
User
>>> [MESSAGE]
Here is the text 'ABC' rendered in ASCII art:
___ ___ ___
/\ \ /\ \ /\ \
/::\ \ /::\ \ /::\ \
/:/\:\ \ /:/\:\ \ /:/\:\ \
/::\~\:\ \ /::\~\:\__\ /:/ \:\ \
/:/\:\ \:\__\ /:/\:\ \:|__| /:/__/ \:\__\
\/__\:\/:/ / \:\~\:\/:/ / \:\ \ \/__/
\::/ / \:\ \::/ / \:\ \
/:/ / \:\/:/ / \:\ \
/:/ / \::/__/ \:\__\
\/__/ ~~ \/__/
>>> [PLANNER->USER]
Here is the text 'ABC' rendered in ASCII art:
___ ___ ___
/\ \ /\ \ /\ \
/::\ \ /::\ \ /::\ \
/:/\:\ \ /:/\:\ \ /:/\:\ \
/::\~\:\ \ /::\~\:\__\ /:/ \:\ \
/:/\:\ \:\__\ /:/\:\ \:|__| /:/__/ \:\__\
\/__\:\/:/ / \:\~\:\/:/ / \:\ \ \/__/
\::/ / \:\ \::/ / \:\ \
/:/ / \:\/:/ / \:\ \
/:/ / \::/__/ \:\__\
\/__/ ~~ \/__/
TaskWeaver: Here is the text 'ABC' rendered in ASCII art:
___ ___ ___
/\ \ /\ \ /\ \
/::\ \ /::\ \ /::\ \
/:/\:\ \ /:/\:\ \ /:/\:\ \
/::\~\:\ \ /::\~\:\__\ /:/ \:\ \
/:/\:\ \:\__\ /:/\:\ \:|__| /:/__/ \:\__\
\/__\:\/:/ / \:\~\:\/:/ / \:\ \ \/__/
\::/ / \:\ \::/ / \:\ \
/:/ / \:\/:/ / \:\ \
/:/ / \::/__/ \:\__\
\/__/ ~~ \/__/
```
26 changes: 23 additions & 3 deletions website/docs/customization/plugin/plugin_intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Here we exhibit an example of the anomaly detection plugin as the following code
import pandas as pd
from pandas.api.types import is_numeric_dtype

from taskWeaver.plugin import Plugin, register_plugin
from taskweaver.plugin import Plugin, register_plugin


@register_plugin
Expand Down Expand Up @@ -178,7 +178,27 @@ returns:

Besides, we also set two optional fields as below:

1. **code**: In cases where multiple plugins map to the same Python code (i.e., the plugin name is different from the
code name), it is essential to specify the code name (code file) in the plugin schema to ensure clarity and accuracy.
1. **code**: Without specifying the code file name, the plugin schema will use the plugin name as the code file name.
For example, the plugin name is `anomaly_detection` and the code file name is `anomaly_detection.py`.
In cases where the plugin name is not the same as the code file name, you can specify the code name (code file) in
the plugin schema to ensure clarity and accuracy. For example, the plugin name is `anomaly_detection` and the code
file name is `anomaly_detection_code.py`. Then, you can specify the code name in the plugin schema as follows:
```yaml
code: anomaly_detection_code
```
Note that the code file name should be the same as the code name without the `.py` extension.
2. **configurations**: When using common code that requires some configuration parameter modifications for different
plugins, it is important to specify these configuration parameters in the plugin schema.
The configuration parameters are specified in the plugin schema as follows:
```yaml
configurations:
key1: value1
key2: value2
```
These configuration parameters can be accessed in the plugin implementation as follows:
```python
self.config.get("key1")
self.config.get("key2")
```


2 changes: 1 addition & 1 deletion website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const sidebars = {
label: 'Plugin',
collapsible: true,
collapsed: true,
items: ['customization/plugin/plugin_intro', 'customization/plugin/plugin_selection', 'customization/plugin/embedding'],
items: ['customization/plugin/plugin_intro', 'customization/plugin/plugin_selection', 'customization/plugin/embedding', 'customization/plugin/develop_plugin'],
},
{
type: 'category',
Expand Down

0 comments on commit 07d6e4a

Please sign in to comment.