-
Notifications
You must be signed in to change notification settings - Fork 44.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(forge): Implement a very very bad, but "functional" agent by default #7021
Changes from 28 commits
f8e9582
26b902d
177d62f
d22762c
a655ebf
2f394d3
7090ca7
a00f65e
a8741db
5dff243
3604484
be4f0d5
fe966c8
fb60162
ef6cc4a
aed8f0e
2899e60
87eabfd
4fc9735
b215505
36d66c6
94962df
960fe39
9d7672f
1d50476
9728fec
2af3724
45b6867
26b582c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,24 @@ | ||
from typing import List | ||
|
||
from ..registry import action | ||
from forge.sdk.agent import Agent | ||
|
||
from ..registry import ActionParameter, action | ||
|
||
|
||
@action( | ||
name="list_files", | ||
description="List files in a directory", | ||
parameters=[ | ||
{ | ||
"name": "path", | ||
"description": "Path to the directory", | ||
"type": "string", | ||
"required": True, | ||
} | ||
ActionParameter( | ||
name="path", | ||
description="Path to the directory", | ||
type="string", | ||
required=True, | ||
) | ||
], | ||
output_type="list[str]", | ||
) | ||
async def list_files(agent, task_id: str, path: str) -> List[str]: | ||
async def list_files(agent: Agent, task_id: str, path: str) -> List[str]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. type hint |
||
""" | ||
List files in a workspace directory | ||
""" | ||
|
@@ -27,22 +29,22 @@ async def list_files(agent, task_id: str, path: str) -> List[str]: | |
name="write_file", | ||
description="Write data to a file", | ||
parameters=[ | ||
{ | ||
"name": "file_path", | ||
"description": "Path to the file", | ||
"type": "string", | ||
"required": True, | ||
}, | ||
{ | ||
"name": "data", | ||
"description": "Data to write to the file", | ||
"type": "bytes", | ||
"required": True, | ||
}, | ||
ActionParameter( | ||
name="file_path", | ||
description="Path to the file", | ||
type="string", | ||
required=True, | ||
), | ||
ActionParameter( | ||
name="data", | ||
description="Data to write to the file", | ||
type="bytes", | ||
required=True, | ||
), | ||
], | ||
output_type="None", | ||
) | ||
async def write_file(agent, task_id: str, file_path: str, data: bytes): | ||
async def write_file(agent: Agent, task_id: str, file_path: str, data: bytes): | ||
""" | ||
Write data to a file | ||
""" | ||
|
@@ -62,16 +64,16 @@ async def write_file(agent, task_id: str, file_path: str, data: bytes): | |
name="read_file", | ||
description="Read data from a file", | ||
parameters=[ | ||
{ | ||
"name": "file_path", | ||
"description": "Path to the file", | ||
"type": "string", | ||
"required": True, | ||
}, | ||
ActionParameter( | ||
name="file_path", | ||
description="Path to the file", | ||
type="string", | ||
required=True, | ||
) | ||
], | ||
output_type="bytes", | ||
) | ||
async def read_file(agent, task_id: str, file_path: str) -> bytes: | ||
async def read_file(agent: Agent, task_id: str, file_path: str) -> bytes: | ||
""" | ||
Read data from a file | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,9 +112,11 @@ def register_abilities(self) -> None: | |
"__init__.py", | ||
"registry.py", | ||
]: | ||
action = os.path.relpath( | ||
action_path, os.path.dirname(__file__) | ||
).replace("/", ".") | ||
action = ( | ||
os.path.relpath(action_path, os.path.dirname(__file__)) | ||
.replace("\\", "/") | ||
.replace("/", ".") | ||
) | ||
try: | ||
module = importlib.import_module( | ||
f".{action[:-3]}", package="forge.actions" | ||
|
@@ -185,9 +187,12 @@ async def run_action( | |
|
||
|
||
if __name__ == "__main__": | ||
import asyncio | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. swifty removal and replacement with more amenable action to not actually having an agent seeded. list_files requires a full agent to be able to be pulled in to actually work |
||
import sys | ||
|
||
sys.path.append("/Users/swifty/dev/forge/forge") | ||
register = ActionRegister(agent=None) | ||
print(register.abilities_description()) | ||
print(register.run_action("abc", "list_files", "/Users/swifty/dev/forge/forge")) | ||
async def run(): | ||
register = ActionRegister(agent=None) | ||
print(register.abilities_description()) | ||
print(await register.run_action("abc", "finish", "./registry.py")) | ||
|
||
asyncio.run(run()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
|
||
from __future__ import annotations | ||
|
||
from forge.sdk.agent import Agent | ||
|
||
COMMAND_CATEGORY = "web_browse" | ||
COMMAND_CATEGORY_TITLE = "Web Browsing" | ||
|
||
|
@@ -38,7 +40,7 @@ | |
|
||
from forge.sdk.errors import CommandExecutionError | ||
|
||
from ..registry import action | ||
from ..registry import ActionParameter, action | ||
|
||
|
||
def extract_hyperlinks(soup: BeautifulSoup, base_url: str) -> list[tuple[str, str]]: | ||
|
@@ -185,25 +187,25 @@ class BrowsingError(CommandExecutionError): | |
name="read_webpage", | ||
description="Read a webpage, and extract specific information from it if a question is specified. If you are looking to extract specific information from the webpage, you should specify a question.", | ||
parameters=[ | ||
{ | ||
"name": "url", | ||
"description": "The URL to visit", | ||
"type": "string", | ||
"required": True, | ||
}, | ||
{ | ||
"name": "question", | ||
"description": "A question that you want to answer using the content of the webpage.", | ||
"type": "string", | ||
"required": False, | ||
}, | ||
ActionParameter( | ||
name="url", | ||
description="The URL to visit", | ||
type="string", | ||
required=True, | ||
), | ||
ActionParameter( | ||
name="question", | ||
description="A question that you want to answer using the content of the webpage.", | ||
type="string", | ||
required=False, | ||
), | ||
], | ||
output_type="string", | ||
) | ||
@validate_url | ||
async def read_webpage( | ||
agent, task_id: str, url: str, question: str = "" | ||
) -> Tuple(str, List[str]): | ||
agent: Agent, task_id: str, url: str, question: str = "" | ||
) -> Tuple(str, list[str]): | ||
"""Browse a website and return the answer and links to the user | ||
|
||
Args: | ||
|
@@ -231,7 +233,9 @@ async def read_webpage( | |
except WebDriverException as e: | ||
# These errors are often quite long and include lots of context. | ||
# Just grab the first line. | ||
msg = e.msg.split("\n")[0] | ||
msg = "An error occurred while trying to load the page" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. type fix |
||
if e.msg: | ||
msg = e.msg.split("\n")[0] | ||
if "net::" in msg: | ||
raise BrowsingError( | ||
f"A networking error occurred while trying to load the page: " | ||
|
@@ -340,9 +344,11 @@ def open_page_in_browser(url: str) -> WebDriver: | |
chromium_driver_path = Path("/usr/bin/chromedriver") | ||
|
||
driver = ChromeDriver( | ||
service=ChromeDriverService(str(chromium_driver_path)) | ||
if chromium_driver_path.exists() | ||
else ChromeDriverService(ChromeDriverManager().install()), | ||
service=( | ||
ChromeDriverService(str(chromium_driver_path)) | ||
if chromium_driver_path.exists() | ||
else ChromeDriverService(ChromeDriverManager().install()) | ||
), | ||
options=options, | ||
) | ||
driver.get(url) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type fix