Skip to content

Commit

Permalink
Merge branch 'docs' of https://github.com/microsoft/TaskWeaver into docs
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangxu0307 committed Dec 20, 2023
2 parents a72c9c2 + 97df31b commit 75db50f
Show file tree
Hide file tree
Showing 23 changed files with 376 additions and 117 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/deploy-website.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: docs

on:
pull_request:
branches: [docs]
path:
- 'website/*'
- '.github/workflows/deploy-website.yml'
push:
branches: [docs]
path:
- 'website/*'
- '.github/workflows/deploy-website.yml'
workflow_dispatch:
merge_group:
types: [checks_requested]

jobs:
gh-release:
runs-on: ubuntu-latest
defaults:
run:
working-directory: website
steps:
- uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: Build website
run: |
if [ -e yarn.lock ]; then
yarn install --frozen-lockfile --ignore-engines
yarn build
elif [ -e package-lock.json ]; then
npm ci
npm run build
else
npm i --legacy-peer-deps
npm run build
fi
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Build output to publish to the `gh-pages` branch:
publish_dir: ./website/build
43 changes: 43 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Python package

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
pytest:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- name: Install taskweaver
run: |
python -m pip install --upgrade pip setuptools wheel
pip install -e .
- name: Test with pytest
run: |
pip install pytest pytest-cov
pytest tests/unit_tests --collect-only
pytest tests/unit_tests -v --junitxml=junit/test-results-${{ matrix.python-version }}.xml --cov=com --cov-report=xml --cov-report=html
- name: Upload pytest test results
uses: actions/upload-artifact@v3
with:
name: pytest-results-${{ matrix.python-version }}
path: junit/test-results-${{ matrix.python-version }}.xml
# Use always() to always run this step to publish test results when there are test failures
if: ${{ always() }}

Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ rounds:
send_from: Planner
send_to: CodeInterpreter
attachment_list: []
- message: Greetings! {ROLE_NAME} can understand the user request and generate syntactically correct python code to complete tasks and can utilize pre-defined plugins in the form of python functions to achieve tasks.
- message: Greetings! I can understand the user request and generate syntactically correct python code to complete tasks and can utilize pre-defined plugins in the form of python functions to achieve tasks.
send_from: CodeInterpreter
send_to: Planner
attachment_list:
- type: text
content: Greetings! {ROLE_NAME} can understand the user request and generate syntactically correct python code to complete tasks and can utilize pre-defined plugins in the form of python functions to achieve tasks.
content: Greetings! I can understand the user request and generate syntactically correct python code to complete tasks and can utilize pre-defined plugins in the form of python functions to achieve tasks.
- type: verification
content: NONE
- type: code_error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ rounds:
send_to: Planner
attachment_list:
- type: thought
content: "{ROLE_NAME} understands that the execution of the previous round has fell."
content: "{ROLE_NAME} understands that the execution of the previous round has failed."
- type: thought
content: "{ROLE_NAME} understands that the file /abc/def.txt does not exist and will not attempt to read it again."
- type: text
Expand Down
2 changes: 2 additions & 0 deletions project/plugins/klarna_search.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ enabled: true
required: false
description: >-
Search and compare prices from thousands of online shops. Only available in the US.
This plugin only takes user requests when searching for merchandise.
If not clear, confirm with the user if they want to search for merchandise from Klarna.
parameters:
- name: query
Expand Down
3 changes: 3 additions & 0 deletions project/plugins/sql_pull_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def __call__(self, query: str):
{schema}
Question: {question}
Please only write the sql query.
Do not add any comments or extra text.
Do not wrap the query in quotes or ```sql.
SQL Query:"""
prompt = ChatPromptTemplate.from_template(template)

Expand Down
5 changes: 3 additions & 2 deletions project/plugins/sql_pull_data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ name: sql_pull_data
enabled: true
required: false
description: >-
Pull data from a SQL database. This plugin takes user requests when obtaining data from database is explicitly mentioned.
Otherwise, it is not sure if the user wants to pull data from database or not.
Pull data from a SQL database.
This plugin takes user requests when obtaining data from database is explicitly mentioned.
Otherwise, confirm with the user if they want to pull data from this database.
The data from this database can only used for anomaly detection.
parameters:
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ pyyaml>=6.0
scikit-learn>=1.2.2
click>=8.0.1
urllib3>=1.26.17
jsonschema==4.17.3
jsonschema==4.20.0
injector>=0.21.0
ijson>=3.2.3
requests>=2.31.0

# Code Execution related
ipykernel==6.26.0
Expand Down
95 changes: 74 additions & 21 deletions taskweaver/code_interpreter/code_generator/code_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _configure(self) -> None:
"prompt_file_path",
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"code_generator_json_prompt.yaml",
"code_generator_prompt.yaml",
),
)
self.example_base_path = self._get_path(
Expand Down Expand Up @@ -147,15 +147,15 @@ def compose_prompt(
self.examples = self.load_examples(plugin_only=self.plugin_only)
for i, example in enumerate(self.examples):
chat_history.extend(
self.compose_conversation(example.rounds, example.plugins),
self.compose_conversation(example.rounds, example.plugins, add_requirements=False),
)

summary = None
if self.config.prompt_compression:
summary, rounds = self.round_compressor.compress_rounds(
rounds,
rounds_formatter=lambda _rounds: str(
self.compose_conversation(_rounds, plugins),
self.compose_conversation(_rounds, plugins, add_requirements=False),
),
use_back_up_engine=True,
prompt_template=self.compression_template,
Expand All @@ -171,27 +171,36 @@ def compose_prompt(
)
return chat_history

def format_attachment(self, attachment: Attachment):
if attachment.type == AttachmentType.thought:
return attachment.content.format(ROLE_NAME=self.role_name)
else:
return attachment.content

def compose_conversation(
self,
rounds: List[Round],
plugins: List[PluginEntry],
add_requirements: bool = False,
summary: Optional[str] = None,
) -> List[ChatMessageType]:
def format_attachment(attachment: Attachment):
if attachment.type == AttachmentType.thought:
return attachment.content.format(ROLE_NAME=self.role_name)
else:
return attachment.content

chat_history: List[ChatMessageType] = []
ignored_types = [
AttachmentType.revise_message,
AttachmentType.verification,
AttachmentType.code_error,
AttachmentType.execution_status,
AttachmentType.execution_result,
]

is_first_post = True
last_post: Post = None
for round_index, conversation_round in enumerate(rounds):
for post_index, post in enumerate(conversation_round.post_list):
# compose user query
user_message = ""
assistant_message = ""

is_final_post = round_index == len(rounds) - 1 and post_index == len(conversation_round.post_list) - 1
if is_first_post:
user_message = (
self.conversation_head_template.format(
Expand All @@ -209,37 +218,53 @@ def format_attachment(attachment: Attachment):
enrichment = ""
if plan is not None:
enrichment = (
f"To complete this request:{user_query}\n\n"
f"To complete this request: {user_query}\n\n"
f"I have drawn up a plan: \n{plan}\n\n"
f"Please proceed with this step of this plan:"
)

user_feedback = "None"
if last_post is not None and last_post.send_from == "CodeInterpreter":
user_feedback = format_code_feedback(last_post)

user_message += self.user_message_head_template.format(
FEEDBACK=user_feedback,
MESSAGE=f"{enrichment}{post.message}",
)
elif post.send_from == "CodeInterpreter" and post.send_to == "CodeInterpreter":
elif post.send_from == post.send_to == "CodeInterpreter":
# for code correction
user_message += self.user_message_head_template.format(
FEEDBACK=format_code_feedback(post),
MESSAGE=f"{post.get_attachment(AttachmentType.revise_message)[0]}",
)

assistant_message = self.post_translator.post_to_raw_text(
post=post,
content_formatter=format_attachment,
content_formatter=self.format_attachment,
if_format_message=False,
if_format_send_to=False,
ignore_types=[AttachmentType.revise_message],
ignored_types=ignored_types,
)
elif post.send_from == "CodeInterpreter" and post.send_to == "Planner":
if is_final_post:
# This user message is added to make the conversation complete
# It is used to make sure the last assistant message has a feedback
# This is only used for examples or context summarization
user_message += self.user_message_head_template.format(
FEEDBACK=format_code_feedback(post),
MESSAGE="This is the feedback.",
)

assistant_message = self.post_translator.post_to_raw_text(
post=post,
content_formatter=format_attachment,
content_formatter=self.format_attachment,
if_format_message=False,
if_format_send_to=False,
ignore_types=[AttachmentType.revise_message],
ignored_types=ignored_types,
)
else:
raise ValueError(f"Invalid post: {post}")
last_post = post

if len(assistant_message) > 0:
chat_history.append(
Expand All @@ -250,11 +275,9 @@ def format_attachment(attachment: Attachment):
)
if len(user_message) > 0:
# add requirements to the last user message
if add_requirements and post_index == len(conversation_round.post_list) - 1:
if is_final_post and add_requirements:
user_message += "\n" + self.query_requirements_template.format(
PLUGIN_ONLY_PROMPT=self.compose_verification_requirements(
plugins,
),
CODE_GENERATION_REQUIREMENTS=self.compose_verification_requirements(plugins),
ROLE_NAME=self.role_name,
)
chat_history.append(
Expand Down Expand Up @@ -300,7 +323,7 @@ def reply(

prompt = self.compose_prompt(rounds, self.plugin_pool)

def early_stop(_type: AttachmentType, value: str):
def early_stop(_type: AttachmentType, value: str) -> bool:
if _type in [AttachmentType.text, AttachmentType.python, AttachmentType.sample]:
return True
else:
Expand Down Expand Up @@ -377,3 +400,33 @@ def format_output_revision_message() -> str:
"Don't surround the JSON with ```json and ```, just send the JSON object directly.\n"
"Please try again."
)


def format_code_feedback(post: Post) -> str:
feedback = ""
verification_status = ""
execution_status = ""
for attachment in post.attachment_list:
if attachment.type == AttachmentType.verification and attachment.content == "CORRECT":
feedback += "## Verification\nI have verified that your code is CORRECT.\n"
verification_status = "CORRECT"
elif attachment.type == AttachmentType.verification and attachment.content == "NONE":
feedback += "## Verification\nNo code verification.\n"
verification_status = "NONE"
elif attachment.type == AttachmentType.verification and attachment.content == "INCORRECT":
feedback += "## Verification\nYour code is INCORRECT with the following error:\n"
verification_status = "INCORRECT"
elif attachment.type == AttachmentType.code_error and verification_status == "INCORRECT":
feedback += f"{attachment.content}\n"
elif attachment.type == AttachmentType.execution_status and attachment.content == "NONE":
feedback += "## Execution\nNo code execution.\n"
execution_status = "NONE"
elif attachment.type == AttachmentType.execution_status and attachment.content == "SUCCESS":
feedback += "## Execution\nYour code has been executed successfully with the following result:\n"
execution_status = "SUCCESS"
elif attachment.type == AttachmentType.execution_status and attachment.content == "FAILURE":
feedback += "## Execution\nYour code has failed to execute with the following error:\n"
execution_status = "FAILURE"
elif attachment.type == AttachmentType.execution_result and execution_status != "NONE":
feedback += f"{attachment.content}\n"
return feedback
Loading

0 comments on commit 75db50f

Please sign in to comment.