pipeline first version

This commit is contained in:
yzlin 2023-11-23 21:59:25 +08:00
parent a0b13c8e0f
commit 3d18dfe2b5
8 changed files with 362 additions and 33 deletions

View file

@ -7,6 +7,7 @@
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Dict, List, Tuple, Union
import traceback
import nbformat
from nbclient import NotebookClient
@ -152,7 +153,7 @@ class ExecutePyCode(ExecuteCode, Action):
return code, language
async def run(self, code: Union[str, Dict, Message], language: str = "python") -> Message:
async def run(self, code: Union[str, Dict, Message], language: str = "python") -> Tuple[str, bool]:
code, language = self._process_code(code, language)
self._display(code, language)
@ -167,13 +168,11 @@ class ExecutePyCode(ExecuteCode, Action):
# TODO: add max_tries for run code.
cell_index = len(self.nb.cells) - 1
await self.nb_client.async_execute_cell(self.nb.cells[-1], cell_index)
return Message(
self.parse_outputs(self.nb.cells[-1].outputs), state="done", sent_from=self.__class__.__name__
)
return self.parse_outputs(self.nb.cells[-1].outputs), True
except Exception as e:
# FIXME: CellExecutionError is hard to read. for example `1\0` raise ZeroDivisionError:
# CellExecutionError('An error occurred while executing the following cell:\n------------------\nz=1/0\n------------------\n\n\n\x1b[0;31m---------------------------------------------------------------------------\x1b[0m\n\x1b[0;31mZeroDivisionError\x1b[0m Traceback (most recent call last)\nCell \x1b[0;32mIn[1], line 1\x1b[0m\n\x1b[0;32m----> 1\x1b[0m z\x1b[38;5;241m=\x1b[39m\x1b[38;5;241;43m1\x1b[39;49m\x1b[38;5;241;43m/\x1b[39;49m\x1b[38;5;241;43m0\x1b[39;49m\n\n\x1b[0;31mZeroDivisionError\x1b[0m: division by zero\n')
return Message(e, state="error", sent_from=self.__class__.__name__)
return traceback.format_exc(), False
else:
# TODO: markdown
raise NotImplementedError(f"Not support this code type : {language}, Only support code!")

View file

@ -7,10 +7,20 @@
from typing import Dict, List, Union
from metagpt.actions import Action
from metagpt.schema import Message
from metagpt.schema import Message, Plan
class BaseWriteAnalysisCode(Action):
class WriteCodeFunction(Action):
async def run(self, context: List[Message], plan: Plan = None, task_guidance: str = ""):
"""Run of a code writing action, used in data analysis or modeling
Args:
context (List[Message]): Action output history, source action denoted by Message.cause_by
plan (Plan, optional): Overall plan. Defaults to None.
task_guidance (str, optional): suggested step breakdown for the current task. Defaults to "".
"""
class WriteCodeFunction(BaseWriteAnalysisCode):
"""Use openai function to generate code."""
def __init__(self, name: str = "", context=None, llm=None) -> str:
@ -44,8 +54,8 @@ class WriteCodeFunction(Action):
return prompt
async def run(
self, prompt: Union[str, List[Dict], Message, List[Message]], system_msg: str = None, **kwargs
) -> Message:
prompt = self.process_msg(prompt, system_msg)
self, context: [List[Message]], plan: Plan = None, task_guidance: str = "", system_msg: str = None, **kwargs
) -> str:
prompt = self.process_msg(context, system_msg)
code_content = await self.llm.aask_code(prompt, **kwargs)
return Message(content=code_content, role="assistant")
return code_content

View file

@ -4,21 +4,41 @@
@Author : orange-crow
@File : plan.py
"""
from typing import Union
from typing import List
import json
from metagpt.actions import Action
from metagpt.prompts.plan import TASK_PLAN_SYSTEM_MSG
from metagpt.schema import Message
from metagpt.utils.common import CodeParser
from metagpt.schema import Message, Task
class WritePlan(Action):
def __init__(self, llm=None):
super().__init__("", None, llm)
PROMPT_TEMPLATE = """
# Context:
__context__
# Current Plan:
__current_plan__
# Task:
Based on the context, write a plan or modify an existing plan of what you should do to achieve the goal. A plan consists of one to __max_tasks__ tasks.
If you are modifying an existing plan, carefully follow the instruction, don't make unnecessary changes.
Output a list of jsons following the format:
[
{
"task_id": str = "unique identifier for a task in plan, can be a ordinal",
"dependent_task_ids": list[str] = "ids of tasks prerequisite to this task",
"instruction": "what you should do in this task, one short phrase or sentence",
},
...
]
"""
async def run(self, context: List[Message], current_plan: str = "", max_tasks: int = 5) -> str:
prompt = (
self.PROMPT_TEMPLATE.replace("__context__", "\n".join([str(ct) for ct in context]))
.replace("__current_plan__", current_plan).replace("__max_tasks__", str(max_tasks))
)
rsp = await self._aask(prompt)
return rsp
async def run(self, prompt: Union[str, Message], role: str = None, system_msg: str = None) -> str:
if role:
system_msg = TASK_PLAN_SYSTEM_MSG.format(role=role)
rsp = self._aask(system_msg + prompt.content) if isinstance(prompt, Message) else await self._aask(system_msg + prompt)
plan = CodeParser.parse_code(None, rsp).split('\n\n')
return Message(plan, role="assistant", sent_from=self.__class__.__name__)
@staticmethod
def rsp_to_tasks(rsp: str) -> List[Task]:
rsp = json.loads(rsp)
tasks = [Task(**task_config) for task_config in rsp]
return tasks