mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-04-24 16:26:36 +02:00
Merge pull request #1897 from Ruyuan37/windows_terminal_adaptation
[terminal.py] Add Windows Terminal support to terminal.py
This commit is contained in:
commit
11cdf466d0
3 changed files with 35 additions and 22 deletions
|
|
@ -5,7 +5,7 @@ default_stages: [ commit ]
|
|||
# 2. pre-commit install
|
||||
# 3. pre-commit run --all-files # make sure all files are clean
|
||||
repos:
|
||||
- repo: https://github.com/pycqa/isort
|
||||
- repo: git@github.com:pycqa/isort.git
|
||||
rev: 5.11.5
|
||||
hooks:
|
||||
- id: isort
|
||||
|
|
@ -15,14 +15,14 @@ repos:
|
|||
.*__init__\.py$
|
||||
)
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
- repo: git@github.com:astral-sh/ruff-pre-commit.git
|
||||
# Ruff version.
|
||||
rev: v0.0.284
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [ --fix ]
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
- repo: git@github.com:psf/black.git
|
||||
rev: 23.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import asyncio
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from asyncio import Queue
|
||||
from asyncio.subprocess import PIPE, STDOUT
|
||||
from typing import Optional
|
||||
|
|
@ -22,8 +23,17 @@ class Terminal:
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.shell_command = ["bash"] # FIXME: should consider windows support later
|
||||
self.command_terminator = "\n"
|
||||
if sys.platform.startswith("win"):
|
||||
self.shell_command = ["cmd.exe"] # Windows
|
||||
self.executable = None
|
||||
self.command_terminator = "\r\n"
|
||||
self.pwd_command = "cd"
|
||||
else:
|
||||
self.shell_command = ["bash"] # Linux / macOS
|
||||
self.executable = "bash"
|
||||
self.command_terminator = "\n"
|
||||
self.pwd_command = "pwd"
|
||||
|
||||
self.stdout_queue = Queue(maxsize=1000)
|
||||
self.observer = TerminalReporter()
|
||||
self.process: Optional[asyncio.subprocess.Process] = None
|
||||
|
|
@ -41,17 +51,17 @@ class Terminal:
|
|||
stdin=PIPE,
|
||||
stdout=PIPE,
|
||||
stderr=STDOUT,
|
||||
executable="bash",
|
||||
executable=self.executable,
|
||||
env=os.environ.copy(),
|
||||
cwd=DEFAULT_WORKSPACE_ROOT.absolute(),
|
||||
cwd=str(DEFAULT_WORKSPACE_ROOT) if sys.platform.startswith("win") else DEFAULT_WORKSPACE_ROOT, # Windows
|
||||
)
|
||||
await self._check_state()
|
||||
|
||||
async def _check_state(self):
|
||||
"""
|
||||
Check the state of the terminal, e.g. the current directory of the terminal process. Useful for agent to understand.
|
||||
Check the state of the terminal, e.g. the current directory.
|
||||
"""
|
||||
output = await self.run_command("pwd")
|
||||
output = await self.run_command(self.pwd_command)
|
||||
logger.info("The terminal is at:", output)
|
||||
|
||||
async def run_command(self, cmd: str, daemon=False) -> str:
|
||||
|
|
@ -74,20 +84,21 @@ class Terminal:
|
|||
output = ""
|
||||
# Remove forbidden commands
|
||||
commands = re.split(r"\s*&&\s*", cmd)
|
||||
skip_cmd = "echo Skipped" if sys.platform.startswith("win") else "true"
|
||||
for cmd_name, reason in self.forbidden_commands.items():
|
||||
# "true" is a pass command in linux terminal.
|
||||
for index, command in enumerate(commands):
|
||||
if cmd_name in command:
|
||||
output += f"Failed to execut {command}. {reason}\n"
|
||||
commands[index] = "true"
|
||||
output += f"Failed to execute {command}. {reason}\n"
|
||||
commands[index] = skip_cmd
|
||||
cmd = " && ".join(commands)
|
||||
|
||||
# Send the command
|
||||
self.process.stdin.write((cmd + self.command_terminator).encode())
|
||||
self.process.stdin.write(
|
||||
f'echo "{END_MARKER_VALUE}"{self.command_terminator}'.encode() # write EOF
|
||||
) # Unique marker to signal command end
|
||||
|
||||
marker_cmd = f"echo {END_MARKER_VALUE}"
|
||||
self.process.stdin.write((marker_cmd + self.command_terminator).encode()) # Unique marker to signal command end
|
||||
await self.process.stdin.drain()
|
||||
|
||||
if daemon:
|
||||
asyncio.create_task(self._read_and_process_output(cmd))
|
||||
else:
|
||||
|
|
@ -116,7 +127,8 @@ class Terminal:
|
|||
This function wraps `run_command`, prepending the necessary Conda activation commands
|
||||
to ensure the specified environment is active for the command's execution.
|
||||
"""
|
||||
cmd = f"conda run -n {env} {cmd}"
|
||||
# windows & linux conda run
|
||||
cmd = f"conda activate {env} && {cmd}" if sys.platform.startswith("win") else f"conda run -n {env} {cmd}"
|
||||
return await self.run_command(cmd, daemon=daemon)
|
||||
|
||||
async def get_stdout_output(self) -> str:
|
||||
|
|
@ -147,10 +159,10 @@ class Terminal:
|
|||
continue
|
||||
*lines, tmp = output.splitlines(True)
|
||||
for line in lines:
|
||||
line = line.decode()
|
||||
line = line.decode(errors="ignore")
|
||||
ix = line.rfind(END_MARKER_VALUE)
|
||||
if ix >= 0:
|
||||
line = line[0:ix]
|
||||
line = line[:ix]
|
||||
if line:
|
||||
await observer.async_report(line, "output")
|
||||
# report stdout in real-time
|
||||
|
|
@ -164,8 +176,9 @@ class Terminal:
|
|||
|
||||
async def close(self):
|
||||
"""Close the persistent shell process."""
|
||||
self.process.stdin.close()
|
||||
await self.process.wait()
|
||||
if self.process:
|
||||
self.process.stdin.close()
|
||||
await self.process.wait()
|
||||
|
||||
|
||||
@register_tool(include_functions=["run"])
|
||||
|
|
|
|||
|
|
@ -113,10 +113,10 @@ TOKEN_COSTS = {
|
|||
"doubao-pro-128k-240515": {"prompt": 0.0007, "completion": 0.0013},
|
||||
"llama3-70b-llama3-70b-instruct": {"prompt": 0.0, "completion": 0.0},
|
||||
"llama3-8b-llama3-8b-instruct": {"prompt": 0.0, "completion": 0.0},
|
||||
"llama-4-Scout-17B-16E-Instruct-FP8" : {"prompt": 0.0, "completion": 0.0}, # start, for Llama API
|
||||
"llama-4-Scout-17B-16E-Instruct-FP8": {"prompt": 0.0, "completion": 0.0}, # start, for Llama API
|
||||
"llama-4-Maverick-17B-128E-Instruct-FP8": {"prompt": 0.0, "completion": 0.0},
|
||||
"llama-3.3-8B-Instruct": {"prompt": 0.0, "completion": 0.0},
|
||||
"llama-3.3-70B-Instruct": {"prompt": 0.0, "completion": 0.0}, # end, for Llama API
|
||||
"llama-3.3-70B-Instruct": {"prompt": 0.0, "completion": 0.0}, # end, for Llama API
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue