mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-04-28 10:26:32 +02:00
fix conflict
This commit is contained in:
commit
d2bd9055f3
29 changed files with 708 additions and 45 deletions
|
|
@ -17,7 +17,7 @@ from metagpt.tools.libs import (
|
|||
deployer,
|
||||
git,
|
||||
)
|
||||
from metagpt.tools.libs.env import get_env, set_get_env_entry, default_get_env, get_env_description
|
||||
from metagpt.tools.libs.env import get_env, set_get_env_entry, default_get_env, get_env_description, get_env_default
|
||||
|
||||
_ = (
|
||||
data_preprocess,
|
||||
|
|
@ -32,6 +32,7 @@ _ = (
|
|||
deployer,
|
||||
git,
|
||||
get_env,
|
||||
get_env_default,
|
||||
get_env_description,
|
||||
set_get_env_entry,
|
||||
default_get_env,
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class CodeReview:
|
|||
if pre:
|
||||
patch_file_content = pre.text
|
||||
else:
|
||||
async with aiofiles.open(patch_path) as f:
|
||||
async with aiofiles.open(patch_path, encoding="utf-8") as f:
|
||||
patch_file_content = await f.read()
|
||||
await EditorReporter().async_report(patch_path)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
import base64
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.tools.tool_registry import register_tool
|
||||
from metagpt.utils import read_docx
|
||||
from metagpt.utils.common import aread_bin, awrite_bin, run_coroutine_sync
|
||||
from metagpt.utils.repo_to_markdown import is_text_file
|
||||
from metagpt.utils.report import EditorReporter
|
||||
|
||||
|
||||
|
|
@ -39,12 +46,26 @@ class Editor(BaseModel):
|
|||
|
||||
def read(self, path: str) -> FileBlock:
|
||||
"""Read the whole content of a file. Using absolute paths as the argument for specifying the file location."""
|
||||
with open(path, "r") as f:
|
||||
self.resource.report(path, "path")
|
||||
lines = f.readlines()
|
||||
is_text, mime_type = run_coroutine_sync(is_text_file, path)
|
||||
if is_text:
|
||||
lines = self._read_text(path)
|
||||
elif mime_type == "application/pdf":
|
||||
lines = self._read_pdf(path)
|
||||
elif mime_type in {
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-word.document.macroEnabled.12",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
||||
"application/vnd.ms-word.template.macroEnabled.12",
|
||||
}:
|
||||
lines = self._read_docx(path)
|
||||
else:
|
||||
return FileBlock(file_path=str(path), block_content="")
|
||||
self.resource.report(str(path), "path")
|
||||
|
||||
lines_with_num = [f"{i + 1:03}|{line}" for i, line in enumerate(lines)]
|
||||
result = FileBlock(
|
||||
file_path=path,
|
||||
file_path=str(path),
|
||||
block_content="".join(lines_with_num),
|
||||
)
|
||||
return result
|
||||
|
|
@ -195,3 +216,63 @@ class Editor(BaseModel):
|
|||
lint_passed = result.returncode == 0
|
||||
lint_message = result.stdout
|
||||
return lint_passed, lint_message
|
||||
|
||||
@staticmethod
|
||||
def _read_text(path: Union[str, Path]) -> List[str]:
|
||||
with open(str(path), "r") as f:
|
||||
lines = f.readlines()
|
||||
return lines
|
||||
|
||||
@staticmethod
|
||||
def _read_pdf(path: Union[str, Path]) -> List[str]:
|
||||
result = run_coroutine_sync(Editor._omniparse_read_file, path)
|
||||
if result:
|
||||
return result
|
||||
|
||||
from llama_index.readers.file import PDFReader
|
||||
|
||||
reader = PDFReader()
|
||||
lines = reader.load_data(file=Path(path))
|
||||
return [i.text for i in lines]
|
||||
|
||||
@staticmethod
|
||||
def _read_docx(path: Union[str, Path]) -> List[str]:
|
||||
result = run_coroutine_sync(Editor._omniparse_read_file, path)
|
||||
if result:
|
||||
return result
|
||||
return read_docx(str(path))
|
||||
|
||||
@staticmethod
|
||||
async def _omniparse_read_file(path: Union[str, Path]) -> Optional[List[str]]:
|
||||
from metagpt.tools.libs import get_env_default
|
||||
from metagpt.utils.omniparse_client import OmniParseClient
|
||||
|
||||
base_url = await get_env_default(key="base_url", app_name="OmniParse", default_value="")
|
||||
if not base_url:
|
||||
return None
|
||||
api_key = await get_env_default(key="api_key", app_name="OmniParse", default_value="")
|
||||
v = await get_env_default(key="timeout", app_name="OmniParse", default_value="120")
|
||||
try:
|
||||
timeout = int(v) or 120
|
||||
except ValueError:
|
||||
timeout = 120
|
||||
|
||||
try:
|
||||
client = OmniParseClient(api_key=api_key, base_url=base_url, max_timeout=timeout)
|
||||
file_data = await aread_bin(filename=path)
|
||||
ret = await client.parse_document(file_input=file_data, bytes_filename=str(path))
|
||||
except (ValueError, Exception) as e:
|
||||
logger.exception(f"{path}: {e}")
|
||||
return None
|
||||
if not ret.images:
|
||||
return [ret.text] if ret.text else None
|
||||
|
||||
result = [ret.text]
|
||||
img_dir = Path(path).parent / (Path(path).name.replace(".", "_") + "_images")
|
||||
img_dir.mkdir(parents=True, exist_ok=True)
|
||||
for i in ret.images:
|
||||
byte_data = base64.b64decode(i.image)
|
||||
filename = img_dir / i.image_name
|
||||
await awrite_bin(filename=filename, data=byte_data)
|
||||
result.append(f"})")
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
@Desc: Implement `get_env`. RFC 216 2.4.2.4.2.
|
||||
"""
|
||||
import os
|
||||
from typing import Dict
|
||||
from typing import Dict, Optional
|
||||
|
||||
|
||||
class EnvKeyNotFoundError(Exception):
|
||||
|
|
@ -15,14 +15,26 @@ class EnvKeyNotFoundError(Exception):
|
|||
super().__init__(info)
|
||||
|
||||
|
||||
def to_app_key(key: str, app_name: str = None) -> str:
|
||||
return f"{app_name}-{key}" if app_name else key
|
||||
|
||||
|
||||
def split_app_key(app_key: str) -> (str, str):
|
||||
if "-" not in app_key:
|
||||
return "", app_key
|
||||
app_name, key = app_key.split("-", 1)
|
||||
return app_name, key
|
||||
|
||||
|
||||
async def default_get_env(key: str, app_name: str = None) -> str:
|
||||
if key in os.environ:
|
||||
return os.environ[key]
|
||||
app_key = to_app_key(key=key, app_name=app_name)
|
||||
if app_key in os.environ:
|
||||
return os.environ[app_key]
|
||||
|
||||
from metagpt.context import Context
|
||||
|
||||
context = Context()
|
||||
val = context.kwargs.get(key, None)
|
||||
val = context.kwargs.get(app_key, None)
|
||||
if val is not None:
|
||||
return val
|
||||
|
||||
|
|
@ -32,14 +44,16 @@ async def default_get_env(key: str, app_name: str = None) -> str:
|
|||
async def default_get_env_description() -> Dict[str, str]:
|
||||
result = {}
|
||||
for k in os.environ.keys():
|
||||
call = f'await get_env(key="{k}", app_name="")'
|
||||
app_name, key = split_app_key(k)
|
||||
call = f'await get_env(key="{key}", app_name="{app_name}")'
|
||||
result[call] = f"Return the value of environment variable `{k}`."
|
||||
|
||||
from metagpt.context import Context
|
||||
|
||||
context = Context()
|
||||
for k in context.kwargs.__dict__.keys():
|
||||
call = f'await get_env(key="{k}", app_name="")'
|
||||
app_name, key = split_app_key(k)
|
||||
call = f'await get_env(key="{key}", app_name="{app_name}")'
|
||||
result[call] = f"Get the value of environment variable `{k}`."
|
||||
return result
|
||||
|
||||
|
|
@ -84,6 +98,37 @@ async def get_env(key: str, app_name: str = None) -> str:
|
|||
return await default_get_env(key=key, app_name=app_name)
|
||||
|
||||
|
||||
async def get_env_default(key: str, app_name: str = None, default_value: str = None) -> Optional[str]:
|
||||
"""
|
||||
Retrieves the value for the specified environment variable key. If the key is not found,
|
||||
returns the default value.
|
||||
|
||||
Args:
|
||||
key (str): The name of the environment variable to retrieve.
|
||||
app_name (str, optional): The name of the application or component to associate with the environment variable.
|
||||
default_value (str, optional): The default value to return if the environment variable is not found.
|
||||
|
||||
Returns:
|
||||
str or None: The value of the environment variable if found, otherwise the default value.
|
||||
|
||||
Example:
|
||||
>>> from metagpt.tools.libs.env import get_env
|
||||
>>> api_key = await get_env_default(key="NOT_EXISTS_API_KEY", default_value="<API_KEY>")
|
||||
>>> print(api_key)
|
||||
<API_KEY>
|
||||
|
||||
>>> from metagpt.tools.libs.env import get_env
|
||||
>>> api_key = await get_env_default(key="NOT_EXISTS_API_KEY", app_name="GITHUB", default_value="<API_KEY>")
|
||||
>>> print(api_key)
|
||||
<API_KEY>
|
||||
|
||||
"""
|
||||
try:
|
||||
return await get_env(key=key, app_name=app_name)
|
||||
except EnvKeyNotFoundError:
|
||||
return default_value
|
||||
|
||||
|
||||
async def get_env_description() -> Dict[str, str]:
|
||||
global _get_env_description_entry
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import asyncio
|
||||
import os
|
||||
from asyncio import Queue
|
||||
from asyncio.subprocess import PIPE, STDOUT
|
||||
from typing import Optional
|
||||
|
|
@ -28,7 +29,7 @@ class Terminal:
|
|||
async def _start_process(self):
|
||||
# Start a persistent shell process
|
||||
self.process = await asyncio.create_subprocess_exec(
|
||||
*self.shell_command, stdin=PIPE, stdout=PIPE, stderr=STDOUT, executable="bash"
|
||||
*self.shell_command, stdin=PIPE, stdout=PIPE, stderr=STDOUT, executable="bash", env=os.environ.copy()
|
||||
)
|
||||
await self._check_state()
|
||||
|
||||
|
|
@ -150,6 +151,7 @@ class Bash(Terminal):
|
|||
|
||||
def __init__(self):
|
||||
"""init"""
|
||||
os.environ["SWE_CMD_WORK_DIR"] = str(DEFAULT_WORKSPACE_ROOT)
|
||||
super().__init__()
|
||||
self.start_flag = False
|
||||
|
||||
|
|
|
|||
|
|
@ -16,4 +16,4 @@ source $REPO_ROOT_DIR/metagpt/tools/swe_agent_commands/defaults.sh
|
|||
source $REPO_ROOT_DIR/metagpt/tools/swe_agent_commands/search.sh
|
||||
source $REPO_ROOT_DIR/metagpt/tools/swe_agent_commands/edit_linting.sh
|
||||
|
||||
export SWE_CMD_WORK_DIR="$REPO_ROOT_DIR/workspace/swe_agent_workdir"
|
||||
echo "SWE_CMD_WORK_DIR: $SWE_CMD_WORK_DIR"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue