fixbug: rfc243

This commit is contained in:
莘权 马 2024-06-15 15:35:47 +08:00
commit e1b3bd3869
17 changed files with 378 additions and 46 deletions

View file

@ -19,11 +19,12 @@ from metagpt.config2 import Config
from metagpt.const import DEFAULT_WORKSPACE_ROOT
from metagpt.context import Context
from metagpt.environment import Environment
from metagpt.environment.mgx.mgx_env import MGXEnv
from metagpt.logs import logger
from metagpt.roles import Architect
from metagpt.roles.di.team_leader import TeamLeader
from metagpt.schema import AIMessage, UserMessage
from metagpt.utils.common import any_to_str, aread, to_markdown_code_block
from metagpt.utils.common import aread, to_markdown_code_block
app = typer.Typer(add_completion=False)
@ -37,19 +38,9 @@ class EnvBuilder(BaseModel):
output_dir: Path
def build(self) -> Environment:
env = Environment(context=self.context)
env = MGXEnv(context=self.context)
team_leader = TeamLeader()
architect = Architect()
architect.tools.extend(
[
"CompressExternalInterfaces",
"DetectInteraction",
"EvaluateTRD",
"WriteTRD",
"WriteFramework",
"EvaluateFramework",
]
)
# Prepare context
use_case_actors = "".join([f"- {v}: {k}\n" for k, v in self.actors.items()])
@ -111,7 +102,8 @@ async def develop(
{user_requirements}
"""
env.publish_message(
UserMessage(content=msg.format(user_requirements="\n".join(user_requirements)), send_to=any_to_str(TeamLeader))
UserMessage(content=msg.format(user_requirements="\n".join(user_requirements)), send_to="Bob"),
user_defined_recipient="Bob",
)
while not env.is_idle:

View file

@ -49,7 +49,7 @@ async def _write_trd(
evaluation_conclusion = ""
interaction_events = ""
trd = ""
while not is_pass:
while not is_pass and (context.cost_manager.total_cost < context.cost_manager.max_budget):
interaction_events = await detect_interaction.run(
user_requirements=r,
use_case_actors=use_case_actors,
@ -99,7 +99,7 @@ async def _write_framework(context: Context, use_case_actors: str, trd: str, ack
is_pass = False
framework = ""
evaluation_conclusion = ""
while not is_pass:
while not is_pass and (context.cost_manager.total_cost < context.cost_manager.max_budget):
try:
framework = await write_framework.run(
use_case_actors=use_case_actors,
@ -175,6 +175,7 @@ def startup(
llm_config: str = typer.Option(default="", help="Low-cost LLM config"),
constraint_filename: str = typer.Option(default="", help="What technical dependency constraints are."),
output_dir: str = typer.Option(default="", help="Output directory."),
investment: float = typer.Option(default=15.0, help="Dollar amount to invest in the AI company."),
):
if llm_config and Path(llm_config).exists():
config = Config.from_yaml_file(Path(llm_config))
@ -182,6 +183,7 @@ def startup(
logger.info("GPT 4 turbo is recommended")
config = Config.default()
ctx = Context(config=config)
ctx.cost_manager.max_budget = investment
asyncio.run(
develop(ctx, user_requirement_filename, actors_filename, acknowledge_filename, constraint_filename, output_dir)

View file

@ -17,7 +17,7 @@ from metagpt.actions.requirement_analysis.framework.evaluate_framework import Ev
from metagpt.actions.requirement_analysis.framework.write_framework import WriteFramework
from metagpt.const import DEFAULT_WORKSPACE_ROOT
from metagpt.tools.tool_registry import register_tool
from metagpt.utils.common import CodeParser, awrite
from metagpt.utils.common import awrite
@register_tool(tags=["software framework"])
@ -25,7 +25,7 @@ async def save_framework(dir_data: str, output_dir: Optional[Union[str, Path]] =
output_dir = Path(output_dir) if output_dir else DEFAULT_WORKSPACE_ROOT / uuid.uuid4().hex
output_dir.mkdir(parents=True, exist_ok=True)
json_data = CodeParser.parse_code(text=dir_data, lang="json")
json_data = dir_data.removeprefix("```json").removesuffix("```")
items = json.loads(json_data)
class Data(BaseModel):
@ -36,6 +36,8 @@ async def save_framework(dir_data: str, output_dir: Optional[Union[str, Path]] =
files = []
for i in items:
v = Data.model_validate(i)
if v.path and v.path[0] == "/":
v.path = "." + v.path
pathname = output_dir / v.path
pathname.mkdir(parents=True, exist_ok=True)
pathname = pathname / v.filename

View file

@ -8,10 +8,16 @@
"""
from metagpt.actions.requirement_analysis import EvaluateAction, EvaluationData
from metagpt.tools.tool_registry import register_tool
from metagpt.utils.common import to_markdown_code_block
@register_tool(include_functions=["run"])
class EvaluateFramework(EvaluateAction):
"""WriteFramework deal with the following situations:
1. Given a TRD and the software framework based on the TRD, evaluate the quality of the software framework.
"""
async def run(
self,
*,
@ -21,6 +27,40 @@ class EvaluateFramework(EvaluateAction):
legacy_output: str,
additional_technical_requirements: str,
) -> EvaluationData:
"""
Run the evaluation of the software framework based on the provided TRD and related parameters.
Args:
use_case_actors (str): A description of the actors involved in the use case.
trd (str): The Technical Requirements Document (TRD) that outlines the requirements for the software framework.
acknowledge (str): External acknowledgments or acknowledgments information related to the framework.
legacy_output (str): The previous versions of software framework returned by `WriteFramework`.
additional_technical_requirements (str): Additional technical requirements that need to be considered during evaluation.
Returns:
EvaluationData: An object containing the results of the evaluation.
Example:
>>> evaluate_framework = EvaluateFramework()
>>> use_case_actors = "- Actor: game player;\\n- System: snake game; \\n- External System: game center;"
>>> trd = "## TRD\\n..."
>>> acknowledge = "## Interfaces\\n..."
>>> framework = '{"path":"balabala", "filename":"...", ...'
>>> constraint = "Using Java language, ..."
>>> evaluation = await evaluate_framework.run(
>>> use_case_actors=use_case_actors,
>>> trd=trd,
>>> acknowledge=acknowledge,
>>> legacy_output=framework,
>>> additional_technical_requirements=constraint,
>>> )
>>> is_pass = evaluation.is_pass
>>> print(is_pass)
True
>>> evaluation_conclusion = evaluation.conclusion
>>> print(evaluation_conclusion)
Balabala...
"""
prompt = PROMPT.format(
use_case_actors=use_case_actors,
trd=to_markdown_code_block(val=trd),

View file

@ -12,10 +12,16 @@ from tenacity import retry, stop_after_attempt, wait_random_exponential
from metagpt.actions import Action
from metagpt.logs import logger
from metagpt.utils.common import CodeParser, general_after_log, to_markdown_code_block
from metagpt.tools.tool_registry import register_tool
from metagpt.utils.common import general_after_log, to_markdown_code_block
@register_tool(include_functions=["run"])
class WriteFramework(Action):
"""WriteFramework deal with the following situations:
1. Given a TRD, write out the software framework.
"""
async def run(
self,
*,
@ -26,6 +32,40 @@ class WriteFramework(Action):
evaluation_conclusion: str,
additional_technical_requirements: str,
) -> str:
"""
Run the action to generate a software framework based on the provided TRD and related information.
Args:
use_case_actors (str): Description of the use case actors involved.
trd (str): Technical Requirements Document detailing the requirements.
acknowledge (str): External acknowledgements or acknowledgements required.
legacy_output (str): Previous version of the software framework returned by `WriteFramework.run`.
evaluation_conclusion (str): Conclusion from the evaluation of the requirements.
additional_technical_requirements (str): Any additional technical requirements.
Returns:
str: The generated software framework as a string.
Example:
>>> write_framework = WriteFramework()
>>> use_case_actors = "- Actor: game player;\\n- System: snake game; \\n- External System: game center;"
>>> trd = "## TRD\\n..."
>>> acknowledge = "## Interfaces\\n..."
>>> legacy_output = '{"path":"balabala", "filename":"...", ...'
>>> evaluation_conclusion = "Balabala..."
>>> constraint = "Using Java language, ..."
>>> framework = await write_framework.run(
>>> use_case_actors=use_case_actors,
>>> trd=trd,
>>> acknowledge=acknowledge,
>>> legacy_output=framework,
>>> evaluation_conclusion=evaluation_conclusion,
>>> additional_technical_requirements=constraint,
>>> )
>>> print(framework)
{"path":"balabala", "filename":"...", ...
"""
prompt = PROMPT.format(
use_case_actors=use_case_actors,
trd=to_markdown_code_block(val=trd),
@ -43,7 +83,13 @@ class WriteFramework(Action):
)
async def _write(self, prompt: str) -> str:
rsp = await self.llm.aask(prompt)
json_data = CodeParser.parse_code(text=rsp, lang="json")
# Do not use `CodeParser` here.
tags = ["```json", "```"]
bix = rsp.find(tags[0])
eix = rsp.rfind(tags[1])
if bix >= 0:
rsp = rsp[bix : eix + len(tags[1])]
json_data = rsp.removeprefix("```json").removesuffix("```")
json.loads(json_data) # validate
return json_data
@ -76,13 +122,12 @@ The descriptions of the interfaces used in the "TRD" can be found in the "Acknow
Develop source code based on the content of the "TRD";
- The `README.md` file should include:
- The folder structure diagram of the entire project;
- Class diagram and sequence diagram in PlantUML format;
- Correspondence between classes, interfaces, and functions with the content in the "TRD" section
- Prerequisites if necessary;
- Installation if necessary;
- Configuration if necessary;
- Usage if necessary;
- The `CLASS.md` file should include class diagram in PlantUML format;
- The `SEQUENCE.md` file should include sequence diagram in PlantUML format;
Return a markdown JSON object list, each object containing:
- a "path" key with a value specifying its path;

View file

@ -18,8 +18,10 @@ Note:
1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst.
2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise, usually the sequence of Product Manager -> Architect -> Project Manager -> Engineer -> (optional: QaEngine if present) -> (optional: DataAnalyst if user requests deployment), each assigned ONE task. When publishing message to Product Manager, you should directly copy the full original user requirement.
3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly.
4. It is helpful for Engineer to have both the system design and the project schedule for writing the code, so include paths of both files (if available) when publishing message to Engineer.
5. If the requirement is writing a TRD, you should assign it to Architect. When publishing message to Architect, you should directly copy the full original user requirement.
4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members.
5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear.
6. It is helpful for Engineer to have both the system design and the project schedule for writing the code, so include paths of both files (if available) when publishing message to Engineer.
7. If the requirement is writing a TRD, you should assign it to Architect. When publishing message to Architect, you should directly copy the full original user requirement.
"""
FINISH_CURRENT_TASK_CMD = """

View file

@ -7,7 +7,18 @@
"""
from metagpt.actions import WritePRD
from metagpt.actions.design_api import WriteDesign
from metagpt.actions.requirement_analysis.framework import (
EvaluateFramework,
WriteFramework,
)
from metagpt.actions.requirement_analysis.trd import (
CompressExternalInterfaces,
DetectInteraction,
EvaluateTRD,
WriteTRD,
)
from metagpt.roles.di.role_zero import RoleZero
from metagpt.utils.common import tool2name
class Architect(RoleZero):
@ -29,9 +40,19 @@ class Architect(RoleZero):
"libraries. Use same language as user requirement"
)
instruction: str = """Use WriteDesign tool to write a system design document"""
instruction: str = """Use WriteDesign tool to write a system design document if a system design is required; Use WriteTRD tool to write a TRD if a TRD is required;"""
max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later
tools: list[str] = ["Editor:write,read,write_content", "RoleZero", "WriteDesign"]
tools: list[str] = [
"Editor:write,read,write_content",
"RoleZero",
"WriteDesign",
"CompressExternalInterfaces",
"DetectInteraction",
"EvaluateTRD",
"WriteTRD",
"WriteFramework",
"EvaluateFramework",
]
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
@ -45,10 +66,17 @@ class Architect(RoleZero):
self._watch({WritePRD})
def _update_tool_execution(self):
wd = WriteDesign()
self.tool_execution_map.update(
{
"WriteDesign.run": wd.run,
"WriteDesign": wd.run, # alias
}
)
write_design = WriteDesign()
self.tool_execution_map.update(tool2name(WriteDesign, ["run"], write_design.run))
compress_external_interfaces = CompressExternalInterfaces()
self.tool_execution_map.update(tool2name(CompressExternalInterfaces, ["run"], compress_external_interfaces.run))
detect_interaction = DetectInteraction()
self.tool_execution_map.update(tool2name(DetectInteraction, ["run"], detect_interaction.run))
evaluate_trd = EvaluateTRD()
self.tool_execution_map.update(tool2name(EvaluateTRD, ["run"], evaluate_trd.run))
write_trd = WriteTRD()
self.tool_execution_map.update(tool2name(WriteTRD, ["run"], write_trd.run))
write_framework = WriteFramework()
self.tool_execution_map.update(tool2name(WriteFramework, ["run"], write_framework.run))
evaluate_framework = EvaluateFramework()
self.tool_execution_map.update(tool2name(EvaluateFramework, ["run"], evaluate_framework.run))

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import inspect
import json
import traceback
from typing import Literal, Tuple
from typing import Callable, Literal, Tuple
from pydantic import model_validator
@ -42,7 +42,7 @@ class RoleZero(Role):
# Tools
tools: list[str] = [] # Use special symbol ["<all>"] to indicate use of all registered tools
tool_recommender: ToolRecommender = None
tool_execution_map: dict[str, callable] = {}
tool_execution_map: dict[str, Callable] = {}
special_tool_commands: list[str] = ["Plan.finish_current_task", "end"]
# Equipped with three basic tools by default for optional use
editor: Editor = Editor()
@ -175,7 +175,7 @@ class RoleZero(Role):
actions_taken += 1
return rsp # return output from the last action
async def _run_commands(self, commands) -> list:
async def _run_commands(self, commands) -> str:
outputs = []
for cmd in commands:
# handle special command first
@ -247,7 +247,7 @@ class RoleZero(Role):
if not isinstance(self.rc.env, MGXEnv):
return "Not in MGXEnv, command will not be executed."
return await self.rc.env.get_human_input(question, sent_from=self)
return await self.rc.env.ask_human(question, sent_from=self)
async def reply_to_human(self, content: str) -> str:
"""Reply to human user with the content provided. Use this when you have a clear answer or solution to the user's question."""

View file

@ -18,7 +18,8 @@ class TeamLeader(RoleZero):
profile: str = "Team Leader"
system_msg: list[str] = [SYSTEM_PROMPT]
max_react_loop: int = 1 # TeamLeader only reacts once each time
# TeamLeader only reacts once each time, but may encounter errors or need to ask human, thus allowing 2 more turns
max_react_loop: int = 3
tools: list[str] = ["Plan", "RoleZero", "TeamLeader"]

View file

@ -14,7 +14,174 @@ class DummyExpRetriever(ExpRetriever):
"""A dummy experience retriever that returns empty string."""
def retrieve(self, context: str = "") -> str:
return ""
return self.EXAMPLE
EXAMPLE: str = """
## example 1
User Requirement: Given some user requirements, write a TRD, and implement the TRD within a software framework.
Explanation:
Given a complete requirement, 要写TRD需要follow如下步骤
1. 调用`CompressExternalInterfaces.run`从acknowledgement中抽取external interfaces的信息
2. 按顺序执行如下步骤
2.1. 执行`DetectInteraction.run`;
2.2. 执行`WriteTRD.run`;
2.3. 执行`EvaluateTRD.run`;
2.4. 检查`EvaluateTRD.run`的结果
2.4.1. 如果`EvaluateTRD.run`的结果被判定为pass则执行步骤3
2.4.2. 如果`EvaluateTRD.run`的结果被判定为deny,则继续执行步骤2
3. 按顺序执行如下步骤
3.1. 执行`WriteFramework.run`;
3.2. 执行`EvaluateFramework.run`;
3.3. 检查`EvaluateFramework.run`的结果
3.3.1. 如果`EvaluateFramework.run`的结果被判定为pass则执行步骤4
3.3.2. 如果`EvaluateFramework.run`的结果被判定为deny,则继续执行步骤3
3.3.3. 如果已经重复执行步骤3超过9次则执行步骤4
4. 执行`save_framework`,`WriteFramework.run`的结果保存下来
```json
[
{
"command_name": "CompressExternalInterfaces.run",
"args": {
"task_id": "1",
"dependent_task_ids": [],
"instruction": "Execute `DetectInteraction.run` to extract external interfaces information from acknowledgement.",
"acknowledge": "## Interfaces\n balabala..."
}
},
{
"command_name": "DetectInteraction.run",
"args": {
"task_id": "2",
"dependent_task_ids": ["1"],
"instruction": "Execute `DetectInteraction.run` to extract external interfaces information from acknowledgement.",
"user_requirements": "This is user requirement balabala...",
"use_case_actors": "These are actors involved in the use case, balabala...",
}
},
{
"command_name": "WriteTRD.run",
"args": {
"task_id": "3",
"dependent_task_ids": ["2"],
"instruction": "Execute `WriteTRD.run` to write TRD",
"user_requirements": "This is user requirement balabala...",
"use_case_actors": "These are actors involved in the use case, balabala...",
"available_external_interfaces": "<compressed_external_interfaces_output> returned by `CompressExternalInterfaces.run`",
"interaction_events": "<detected_interaction_events_output> returned by `DetectInteraction.run`"
}
},
{
"command_name": "EvaluateTRD.run",
"args": {
"task_id": "4",
"dependent_task_ids": ["3"],
"instruction": "Execute `EvaluateTRD.run` to evaluate the TRD",
"user_requirements": "This is user requirement balabala...",
"use_case_actors": "These are actors involved in the use case, balabala...",
"available_external_interfaces": "<compressed_external_interfaces_output> returned by `CompressExternalInterfaces.run`",
"interaction_events": "<detected_interaction_events_output>",
"trd": "<trd> returned by `EvaluateTRD.run`"
}
},
{
"command_name": "DetectInteraction.run",
"args": {
"task_id": "5",
"dependent_task_ids": ["4"],
"instruction": "Execute `DetectInteraction.run` to extract external interfaces information from acknowledgement.",
"user_requirements": "This is user requirement balabala...",
"use_case_actors": "These are actors involved in the use case, balabala...",
"evaluation_conclusion": "<evaluation_conclusion> returned by `EvaluateTRD.run`"
}
},
{
"command_name": "WriteTRD.run",
"args": {
"task_id": "6",
"dependent_task_ids": ["5"],
"instruction": "Execute `WriteTRD.run` to write TRD",
"user_requirements": "This is user requirement balabala...",
"use_case_actors": "These are actors involved in the use case, balabala...",
"available_external_interfaces": "<compressed_external_interfaces_output> returned by `CompressExternalInterfaces.run`",
"interaction_events": "<detected_interaction_events_output> returned by `DetectInteraction.run`",
"previous_version_trd": "<trd> returned by `WriteTRD.run`"
}
},
{
"command_name": "EvaluateTRD.run",
"args": {
"task_id": "7",
"dependent_task_ids": ["6"],
"instruction": "Execute `EvaluateTRD.run` to evaluate the TRD",
"user_requirements": "This is user requirement balabala...",
"use_case_actors": "These are actors involved in the use case, balabala...",
"available_external_interfaces": "<compressed_external_interfaces_output> returned by `CompressExternalInterfaces.run`",
"interaction_events": "<detected_interaction_events_output> returned by `DetectInteraction.run`",
"trd": "<trd> returned by `WriteTRD.run`",
}
},
{
"command_name": "WriteFramework.run",
"args": {
"task_id": "8",
"dependent_task_ids": ["7"],
"instruction": "Execute `WriteFramework.run` to write a software framework according to the TRD",
"use_case_actors": "These are actors involved in the use case, balabala...",
"trd": "<trd> returned by `WriteTRD.run`",
"acknowledge": "## Interfaces\n balabala...",
"additional_technical_requirements": "These are additional technical requirements, balabala...",
}
},
{
"command_name": "EvaluateFramework.run",
"args": {
"task_id": "9",
"dependent_task_ids": ["8"],
"instruction": "Execute `EvaluateFramework.run` to evaluate the software framework returned by `WriteFramework.run`",
"use_case_actors": "These are actors involved in the use case, balabala...",
"trd": "<trd> returned by `WriteTRD.run`",
"acknowledge": "## Interfaces\n balabala...",
"legacy_output": "<framework> returned by `WriteFramework.run`",
"additional_technical_requirements": "These are additional technical requirements, balabala...",
}
},
{
"command_name": "WriteFramework.run",
"args": {
"task_id": "10",
"dependent_task_ids": ["9"],
"instruction": "Execute `WriteFramework.run` to write a software framework according to the TRD",
"use_case_actors": "These are actors involved in the use case, balabala...",
"trd": "<trd> returned by `WriteTRD.run`",
"acknowledge": "## Interfaces\n balabala...",
"additional_technical_requirements": "These are additional technical requirements, balabala...",
}
},
{
"command_name": "EvaluateFramework.run",
"args": {
"task_id": "11",
"dependent_task_ids": ["10"],
"instruction": "Execute `EvaluateFramework.run` to evaluate the software framework returned by `WriteFramework.run`",
"use_case_actors": "These are actors involved in the use case, balabala...",
"trd": "<trd> returned by `WriteTRD.run`",
"acknowledge": "## Interfaces\n balabala...",
"legacy_output": "<framework> returned by `WriteFramework.run`",
"additional_technical_requirements": "These are additional technical requirements, balabala...",
}
},
{
"command_name": "save_framework",
"args": {
"task_id": "12",
"dependent_task_ids": ["11"],
"instruction": "Execute `save_framework` to save the software framework returned by `WriteFramework.run`",
"dir_data": "<framework> returned by `WriteFramework.run`",
}
}
]
```
"""
class SimpleExpRetriever(ExpRetriever):
@ -83,6 +250,9 @@ class SimpleExpRetriever(ExpRetriever):
"args": {
"content": "I have assigned the tasks to the team members. Alice will create the PRD, Bob will design the software architecture, Eve will break down the architecture into tasks, Alex will implement the core game logic, and Edward will write comprehensive tests. The team will work on the project accordingly",
}
},
{
"command_name": "end"
}
]
```
@ -113,6 +283,9 @@ class SimpleExpRetriever(ExpRetriever):
"args": {
"content": "I have assigned the task to David. He will break down the task further by himself and starts solving it.",
}
},
{
"command_name": "end"
}
]
```
@ -142,6 +315,9 @@ class SimpleExpRetriever(ExpRetriever):
"args": {
"content": "Alice has completed the PRD. I have marked her task as finished and sent the PRD to Bob. Bob will work on the software architecture.",
}
},
{
"command_name": "end"
}
]
```
@ -156,13 +332,16 @@ class SimpleExpRetriever(ExpRetriever):
"args": {
"content": "The team is currently working on ... We have completed ...",
}
},
{
"command_name": "end"
}
]
```
"""
def retrieve(self, context: str = "") -> str:
return "" # byRFC243 self.EXAMPLE
return self.EXAMPLE
class KeywordExpRetriever(ExpRetriever):
@ -213,6 +392,7 @@ Explanation: Launching a service requires Terminal tool with daemon mode, write
"assignee": "David"
}
},
]
"""

View file

@ -189,8 +189,8 @@ class Browser:
async def _view(self, keep_len: int = 5000) -> str:
"""simulate human viewing the current page, return the visible text with links"""
# visible_text_with_links = await self.current_page.evaluate(VIEW_CONTENT_JS)
# print("The visible text and their links (if any): ", visible_text_with_links[:keep_len])
visible_text_with_links = await self.current_page.evaluate(VIEW_CONTENT_JS)
print("The visible text and their links (if any): ", visible_text_with_links[:keep_len])
# html_content = await self._view_page_html(keep_len=keep_len)
# print("The html content: ", html_content)

View file

@ -1,4 +1,5 @@
import os
import re
import shutil
import subprocess
@ -26,6 +27,9 @@ class Editor:
def write(self, path: str, content: str):
"""Write the whole content to a file. When used, make sure content arg contains the full content of the file."""
if len(re.findall(r"\\n", content)) >= 5:
# A very raw rule to correct the content: Many \\n suggests all new line characters are mistaken as \\n whereas the correct one should be \n
content = content.replace("\\n", "\n")
directory = os.path.dirname(path)
if directory and not os.path.exists(directory):
os.makedirs(directory)

View file

@ -141,6 +141,8 @@ async def git_create_pull(
Returns:
PullRequest: The created pull request.
"""
from metagpt.utils.git_repository import GitRepository
return await GitRepository.create_pull(
base=base,
head=head,
@ -187,4 +189,6 @@ async def git_create_issue(
Returns:
Issue: The created issue.
"""
from metagpt.utils.git_repository import GitRepository
return await GitRepository.create_issue(repo_name=repo_name, title=title, body=body, access_token=access_token)

View file

@ -26,7 +26,7 @@ class Terminal:
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
executable="/bin/bash"
executable="/bin/bash",
)
self.stdout_queue = Queue()
self.observer = TerminalReporter()

View file

@ -26,7 +26,7 @@ import sys
import traceback
from io import BytesIO
from pathlib import Path
from typing import Any, Callable, List, Literal, Optional, Tuple, Union
from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union
from urllib.parse import quote, unquote
import aiofiles
@ -1013,3 +1013,34 @@ async def save_json_to_markdown(content: str, output_filename: str | Path):
logger.warning(f"An unexpected error occurred: {e}")
return
await awrite(filename=output_filename, data=json_to_markdown(m))
def tool2name(cls, methods: List[str], entry) -> Dict[str, Any]:
"""
Generates a mapping of class methods to a given entry with class name as a prefix.
Args:
cls: The class from which the methods are derived.
methods (List[str]): A list of method names as strings.
entry (Any): The entry to be mapped to each method.
Returns:
Dict[str, Any]: A dictionary where keys are method names prefixed with the class name and
values are the given entry. If the number of methods is less than 2,
the dictionary will contain a single entry with the class name as the key.
Example:
>>> class MyClass:
>>> pass
>>>
>>> tool2name(MyClass, ['method1', 'method2'], 'some_entry')
{'MyClass.method1': 'some_entry', 'MyClass.method2': 'some_entry'}
>>> tool2name(MyClass, ['method1'], 'some_entry')
{'MyClass': 'some_entry', 'MyClass.method1': 'some_entry'}
"""
class_name = cls.__name__
mappings = {f"{class_name}.{i}": entry for i in methods}
if len(mappings) < 2:
mappings[class_name] = entry
return mappings

View file

@ -1,2 +1,3 @@
- 基于dingtalk框架编码
- 用java编程语言
- 用java编程语言
- 接口类的功能要放到implement子类中实现;

View file

@ -1,5 +1,5 @@
[
"【按国家名维度搜索】\n法务查询者在国际小超人钉钉小程序搜索框中进行检索时采用 typeahead只能下拉选择数据库中有的国家名。",
"法务查询者从国际小超人钉钉小程序UI侧的国家名称列表中选中国家名进入国家详情界面。\n法务查询者从国家详情中的业务线名列表中选出业务线名。",
"【按国家名维度搜索】\n法务查询者在国际小超人钉钉小程序搜索框中进行检索时采用 typeahead只能下拉选择法务中台中有的国家名。",
"法务查询者从国际小超人钉钉小程序UI侧的国家名称列表中选中国家名进入国家详情界面。\n在国家详情界面里,法务查询者从国家详情中的业务线名列表中选出业务线名。",
"国际小超人钉钉小程序用国家代码和业务代码做参数,查询法律意见详情,然后将结果展示给法务查询者。"
]