mirror of
https://github.com/aljazceru/Auto-GPT.git
synced 2025-12-27 10:54:35 +01:00
Fix Forge (#22)
Signed-off-by: Merwane Hamadi <merwanehamadi@gmail.com>
This commit is contained in:
@@ -60,10 +60,8 @@ class Agent:
|
||||
"""
|
||||
try:
|
||||
task = await self.db.create_task(
|
||||
input=task_request.input if task_request.input else None,
|
||||
additional_input=task_request.additional_input
|
||||
if task_request.additional_input
|
||||
else None,
|
||||
input=task_request.input,
|
||||
additional_input=task_request.additional_input,
|
||||
)
|
||||
return task
|
||||
except Exception as e:
|
||||
@@ -112,10 +110,8 @@ class Agent:
|
||||
if step_request.input != "y":
|
||||
step = await self.db.create_step(
|
||||
task_id=task_id,
|
||||
input=step_request.input if step_request else None,
|
||||
additional_properties=step_request.additional_input
|
||||
if step_request
|
||||
else None,
|
||||
input=step_request,
|
||||
additional_input=step_request.additional_input,
|
||||
)
|
||||
# utils.run
|
||||
artifacts = run(step.input)
|
||||
@@ -143,7 +139,7 @@ class Agent:
|
||||
step = await self.db.create_step(
|
||||
task_id=task_id,
|
||||
input="y",
|
||||
additional_properties=None,
|
||||
additional_input={},
|
||||
)
|
||||
step.status = "completed"
|
||||
step.is_last = True
|
||||
@@ -224,7 +220,7 @@ class Agent:
|
||||
Get an artifact by ID.
|
||||
"""
|
||||
try:
|
||||
artifact = await self.db.get_artifact(task_id, artifact_id)
|
||||
artifact = await self.db.get_artifact(artifact_id)
|
||||
retrieved_artifact = await self.load_from_uri(artifact.uri, artifact_id)
|
||||
path = artifact.file_name
|
||||
with open(path, "wb") as f:
|
||||
|
||||
@@ -16,7 +16,7 @@ def agent():
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_task(agent):
|
||||
task_request = TaskRequestBody(
|
||||
input="test_input", additional_input="additional_test_input"
|
||||
input="test_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
task: Task = await agent.create_task(task_request)
|
||||
assert task.input == "test_input"
|
||||
@@ -25,7 +25,7 @@ async def test_create_task(agent):
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_tasks(agent):
|
||||
task_request = TaskRequestBody(
|
||||
input="test_input", additional_input="additional_test_input"
|
||||
input="test_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
task = await agent.create_task(task_request)
|
||||
tasks = await agent.list_tasks()
|
||||
@@ -35,7 +35,7 @@ async def test_list_tasks(agent):
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_task(agent):
|
||||
task_request = TaskRequestBody(
|
||||
input="test_input", additional_input="additional_test_input"
|
||||
input="test_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
task = await agent.create_task(task_request)
|
||||
retrieved_task = await agent.get_task(task.task_id)
|
||||
@@ -46,26 +46,26 @@ async def test_get_task(agent):
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_and_execute_step(agent):
|
||||
task_request = TaskRequestBody(
|
||||
input="test_input", additional_input="additional_test_input"
|
||||
input="test_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
task = await agent.create_task(task_request)
|
||||
step_request = StepRequestBody(
|
||||
input="step_input", additional_input="additional_step_input"
|
||||
input="step_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
step = await agent.create_and_execute_step(task.task_id, step_request)
|
||||
assert step.input == "step_input"
|
||||
assert step.additional_input == "additional_step_input"
|
||||
assert step.additional_input == {"input": "additional_test_input"}
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_step(agent):
|
||||
task_request = TaskRequestBody(
|
||||
input="test_input", additional_input="additional_test_input"
|
||||
input="test_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
task = await agent.create_task(task_request)
|
||||
step_request = StepRequestBody(
|
||||
input="step_input", additional_input="additional_step_input"
|
||||
input="step_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
step = await agent.create_and_execute_step(task.task_id, step_request)
|
||||
retrieved_step = await agent.get_step(task.task_id, step.step_id)
|
||||
@@ -83,7 +83,7 @@ async def test_list_artifacts(agent):
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_artifact(agent):
|
||||
task_request = TaskRequestBody(
|
||||
input="test_input", additional_input="additional_test_input"
|
||||
input="test_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
task = await agent.create_task(task_request)
|
||||
artifact_request = ArtifactRequestBody(file=None, uri="test_uri")
|
||||
@@ -95,7 +95,7 @@ async def test_create_artifact(agent):
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_artifact(agent):
|
||||
task_request = TaskRequestBody(
|
||||
input="test_input", additional_input="additional_test_input"
|
||||
input="test_input", additional_input={"input": "additional_test_input"}
|
||||
)
|
||||
task = await agent.create_task(task_request)
|
||||
artifact_request = ArtifactRequestBody(file=None, uri="test_uri")
|
||||
|
||||
@@ -7,9 +7,17 @@ IT IS NOT ADVISED TO USE THIS IN PRODUCTION!
|
||||
import datetime
|
||||
import math
|
||||
import uuid
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, String, create_engine
|
||||
from sqlalchemy import (
|
||||
JSON,
|
||||
Boolean,
|
||||
Column,
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
String,
|
||||
create_engine,
|
||||
)
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import DeclarativeBase, joinedload, relationship, sessionmaker
|
||||
|
||||
@@ -29,7 +37,7 @@ class TaskModel(Base):
|
||||
|
||||
task_id = Column(String, primary_key=True, index=True)
|
||||
input = Column(String)
|
||||
additional_input = Column(String)
|
||||
additional_input = Column(JSON)
|
||||
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
modified_at = Column(
|
||||
DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow
|
||||
@@ -52,7 +60,7 @@ class StepModel(Base):
|
||||
DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow
|
||||
)
|
||||
|
||||
additional_properties = Column(String)
|
||||
additional_input = Column(JSON)
|
||||
artifacts = relationship("ArtifactModel", back_populates="step")
|
||||
|
||||
|
||||
@@ -105,7 +113,7 @@ def convert_to_step(step_model: StepModel, debug_enabled: bool = False) -> Step:
|
||||
status=status,
|
||||
artifacts=step_artifacts,
|
||||
is_last=step_model.is_last == 1,
|
||||
additional_properties=step_model.additional_properties,
|
||||
additional_input=step_model.additional_input,
|
||||
)
|
||||
|
||||
|
||||
@@ -131,7 +139,7 @@ class AgentDB:
|
||||
self.Session = sessionmaker(bind=self.engine)
|
||||
|
||||
async def create_task(
|
||||
self, input: Optional[str], additional_input: Optional[TaskInput] = None
|
||||
self, input: Optional[str], additional_input: Optional[TaskInput] = {}
|
||||
) -> Task:
|
||||
if self.debug_enabled:
|
||||
LOG.debug("Creating new task")
|
||||
@@ -141,9 +149,7 @@ class AgentDB:
|
||||
new_task = TaskModel(
|
||||
task_id=str(uuid.uuid4()),
|
||||
input=input,
|
||||
additional_input=additional_input.__root__
|
||||
if additional_input
|
||||
else None,
|
||||
additional_input=additional_input,
|
||||
)
|
||||
session.add(new_task)
|
||||
session.commit()
|
||||
@@ -165,7 +171,7 @@ class AgentDB:
|
||||
task_id: str,
|
||||
input: str,
|
||||
is_last: bool = False,
|
||||
additional_properties: Optional[Dict[str, str]] = None,
|
||||
additional_input: Optional[Dict[str, Any]] = {},
|
||||
) -> Step:
|
||||
if self.debug_enabled:
|
||||
LOG.debug(f"Creating new step for task_id: {task_id}")
|
||||
@@ -174,11 +180,11 @@ class AgentDB:
|
||||
new_step = StepModel(
|
||||
task_id=task_id,
|
||||
step_id=str(uuid.uuid4()),
|
||||
name=input,
|
||||
input=input,
|
||||
name=input.name,
|
||||
input=input.input,
|
||||
status="created",
|
||||
is_last=is_last,
|
||||
additional_properties=additional_properties,
|
||||
additional_input=additional_input,
|
||||
)
|
||||
session.add(new_step)
|
||||
session.commit()
|
||||
@@ -299,7 +305,7 @@ class AgentDB:
|
||||
task_id: str,
|
||||
step_id: str,
|
||||
status: str,
|
||||
additional_properties: Optional[Dict[str, str]] = None,
|
||||
additional_input: Optional[Dict[str, Any]] = {},
|
||||
) -> Step:
|
||||
if self.debug_enabled:
|
||||
LOG.debug(f"Updating step with task_id: {task_id} and step_id: {step_id}")
|
||||
@@ -311,7 +317,7 @@ class AgentDB:
|
||||
.first()
|
||||
):
|
||||
step.status = status
|
||||
step.additional_properties = additional_properties
|
||||
step.additional_input = additional_input
|
||||
session.commit()
|
||||
return await self.get_step(task_id, step_id)
|
||||
else:
|
||||
@@ -364,8 +370,6 @@ class AgentDB:
|
||||
.limit(per_page)
|
||||
.all()
|
||||
)
|
||||
if not tasks:
|
||||
raise NotFoundError("No tasks found")
|
||||
total = session.query(TaskModel).count()
|
||||
pages = math.ceil(total / per_page)
|
||||
pagination = Pagination(
|
||||
@@ -400,8 +404,6 @@ class AgentDB:
|
||||
.limit(per_page)
|
||||
.all()
|
||||
)
|
||||
if not steps:
|
||||
raise NotFoundError("No steps found")
|
||||
total = session.query(StepModel).filter_by(task_id=task_id).count()
|
||||
pages = math.ceil(total / per_page)
|
||||
pagination = Pagination(
|
||||
@@ -436,8 +438,6 @@ class AgentDB:
|
||||
.limit(per_page)
|
||||
.all()
|
||||
)
|
||||
if not artifacts:
|
||||
raise NotFoundError("No artifacts found")
|
||||
total = session.query(ArtifactModel).filter_by(task_id=task_id).count()
|
||||
pages = math.ceil(total / per_page)
|
||||
pagination = Pagination(
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
"""
|
||||
Routes for the Agent Service.
|
||||
|
||||
This module defines the API routes for the Agent service. While there are multiple endpoints provided by the service,
|
||||
This module defines the API routes for the Agent service. While there are multiple endpoints provided by the service,
|
||||
the ones that require special attention due to their complexity are:
|
||||
|
||||
1. `execute_agent_task_step`:
|
||||
This route is significant because this is where the agent actually performs the work. The function handles
|
||||
executing the next step for a task based on its current state, and it requires careful implementation to ensure
|
||||
1. `execute_agent_task_step`:
|
||||
This route is significant because this is where the agent actually performs the work. The function handles
|
||||
executing the next step for a task based on its current state, and it requires careful implementation to ensure
|
||||
all scenarios (like the presence or absence of steps or a step marked as `last_step`) are handled correctly.
|
||||
|
||||
2. `upload_agent_task_artifacts`:
|
||||
This route allows for the upload of artifacts, supporting various URI types (e.g., s3, gcs, ftp, http).
|
||||
The support for different URI types makes it a bit more complex, and it's important to ensure that all
|
||||
supported URI types are correctly managed. NOTE: The Auto-GPT team will eventually handle the most common
|
||||
2. `upload_agent_task_artifacts`:
|
||||
This route allows for the upload of artifacts, supporting various URI types (e.g., s3, gcs, ftp, http).
|
||||
The support for different URI types makes it a bit more complex, and it's important to ensure that all
|
||||
supported URI types are correctly managed. NOTE: The Auto-GPT team will eventually handle the most common
|
||||
uri types for you.
|
||||
|
||||
3. `create_agent_task`:
|
||||
While this is a simpler route, it plays a crucial role in the workflow, as it's responsible for the creation
|
||||
3. `create_agent_task`:
|
||||
While this is a simpler route, it plays a crucial role in the workflow, as it's responsible for the creation
|
||||
of a new task.
|
||||
|
||||
Developers and contributors should be especially careful when making modifications to these routes to ensure
|
||||
Developers and contributors should be especially careful when making modifications to these routes to ensure
|
||||
consistency and correctness in the system's behavior.
|
||||
"""
|
||||
import json
|
||||
@@ -102,7 +102,11 @@ async def create_agent_task(request: Request, task_request: TaskRequestBody) ->
|
||||
|
||||
try:
|
||||
task_request = await agent.create_task(task_request)
|
||||
return Response(content=task_request.json(), status_code=200)
|
||||
return Response(
|
||||
content=task_request.json(),
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
except NotFoundError:
|
||||
return Response(
|
||||
content=json.dumps({"error": "Task not found"}),
|
||||
@@ -161,7 +165,11 @@ async def list_agent_tasks(
|
||||
agent = request["agent"]
|
||||
try:
|
||||
tasks = await agent.list_tasks(page, page_size)
|
||||
return Response(content=tasks.json(), status_code=200)
|
||||
return Response(
|
||||
content=tasks.json(),
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
except NotFoundError:
|
||||
return Response(
|
||||
content=json.dumps({"error": "Task not found"}),
|
||||
@@ -232,7 +240,11 @@ async def get_agent_task(request: Request, task_id: str) -> Task:
|
||||
agent = request["agent"]
|
||||
try:
|
||||
task = await agent.get_task(task_id)
|
||||
return Response(content=task.json(), status_code=200)
|
||||
return Response(
|
||||
content=task.json(),
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
except NotFoundError:
|
||||
return Response(
|
||||
content=json.dumps({"error": "Task not found"}),
|
||||
@@ -293,7 +305,11 @@ async def list_agent_task_steps(
|
||||
agent = request["agent"]
|
||||
try:
|
||||
steps = await agent.list_steps(task_id, page, page_size)
|
||||
return Response(content=steps.json(), status_code=200)
|
||||
return Response(
|
||||
content=steps.json(),
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
except NotFoundError:
|
||||
return Response(
|
||||
content=json.dumps({"error": "Task not found"}),
|
||||
@@ -355,7 +371,11 @@ async def execute_agent_task_step(
|
||||
agent = request["agent"]
|
||||
try:
|
||||
step = await agent.create_and_execute_step(task_id, step)
|
||||
return Response(content=step.json(), status_code=200)
|
||||
return Response(
|
||||
content=step.json(),
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
except NotFoundError:
|
||||
return Response(
|
||||
content=json.dumps({"error": f"Task not found {task_id}"}),
|
||||
@@ -462,7 +482,7 @@ async def list_agent_task_artifacts(
|
||||
agent = request["agent"]
|
||||
try:
|
||||
artifacts = await agent.list_artifacts(task_id, page, page_size)
|
||||
return Response(content=artifacts.json(), status_code=200)
|
||||
return artifacts
|
||||
except NotFoundError:
|
||||
return Response(
|
||||
content=json.dumps({"error": "Task not found"}),
|
||||
@@ -522,21 +542,31 @@ async def upload_agent_task_artifacts(
|
||||
agent = request["agent"]
|
||||
if file is None and uri is None:
|
||||
return Response(
|
||||
content={"error": "Either file or uri must be specified"}, status_code=404
|
||||
content=json.dumps({"error": "Either file or uri must be specified"}),
|
||||
status_code=404,
|
||||
media_type="application/json",
|
||||
)
|
||||
if file is not None and uri is not None:
|
||||
return Response(
|
||||
content={"error": "Both file and uri cannot be specified at the same time"},
|
||||
content=json.dumps(
|
||||
{"error": "Both file and uri cannot be specified at the same time"}
|
||||
),
|
||||
status_code=404,
|
||||
media_type="application/json",
|
||||
)
|
||||
if uri is not None and not uri.startswith(("http://", "https://", "file://")):
|
||||
return Response(
|
||||
content={"error": "URI must start with http, https or file"},
|
||||
content=json.dumps({"error": "URI must start with http, https or file"}),
|
||||
status_code=404,
|
||||
media_type="application/json",
|
||||
)
|
||||
try:
|
||||
artifact = await agent.create_artifact(task_id, file, uri)
|
||||
return Response(content=artifact.json(), status_code=200)
|
||||
return Response(
|
||||
content=artifact.json(),
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
except NotFoundError:
|
||||
return Response(
|
||||
content=json.dumps({"error": "Task not found"}),
|
||||
|
||||
@@ -63,10 +63,11 @@ class StepOutput(BaseModel):
|
||||
class TaskRequestBody(BaseModel):
|
||||
input: str = Field(
|
||||
...,
|
||||
min_length=1,
|
||||
description="Input prompt for the task.",
|
||||
example="Write the words you receive to the file 'output.txt'.",
|
||||
)
|
||||
additional_input: Optional[TaskInput] = None
|
||||
additional_input: Optional[TaskInput] = {}
|
||||
|
||||
|
||||
class Task(TaskRequestBody):
|
||||
@@ -102,9 +103,12 @@ class StepRequestBody(BaseModel):
|
||||
None, description="The name of the task step.", example="Write to file"
|
||||
)
|
||||
input: str = Field(
|
||||
..., description="Input prompt for the step.", example="Washington"
|
||||
...,
|
||||
min_length=1,
|
||||
description="Input prompt for the step.",
|
||||
example="Washington",
|
||||
)
|
||||
additional_input: Optional[StepInput] = None
|
||||
additional_input: Optional[StepInput] = {}
|
||||
|
||||
|
||||
class Status(Enum):
|
||||
@@ -147,7 +151,7 @@ class Step(StepRequestBody):
|
||||
description="Output of the task step.",
|
||||
example="I am going to use the write_to_file command and write Washington to a file called output.txt <write_to_file('output.txt', 'Washington')",
|
||||
)
|
||||
additional_output: Optional[StepOutput] = None
|
||||
additional_output: Optional[StepOutput] = {}
|
||||
artifacts: Optional[List[Artifact]] = Field(
|
||||
[], description="A list of artifacts that the step has produced."
|
||||
)
|
||||
|
||||
@@ -32,6 +32,7 @@ def chat_completion_request(
|
||||
functions: typing.List[typing.Dict[str, str]] | None = None,
|
||||
function_call: typing.Optional[str] = None,
|
||||
model: str = "gpt-3.5-turbo",
|
||||
temperature: float = 0,
|
||||
) -> typing.Union[typing.Dict[str, typing.Any], Exception]:
|
||||
"""Generate a response to a list of messages using OpenAI's API"""
|
||||
try:
|
||||
@@ -39,6 +40,7 @@ def chat_completion_request(
|
||||
model=model,
|
||||
messages=messages,
|
||||
user="TheForge",
|
||||
temperature=temperature,
|
||||
)
|
||||
except Exception as e:
|
||||
LOG.info("Unable to generate ChatCompletion response")
|
||||
@@ -80,30 +82,31 @@ def execute_plan(plan: typing.List[str]) -> None:
|
||||
def plan(task: str) -> typing.List[str]:
|
||||
"""Returns a list of tasks that needs to be executed to complete the task"""
|
||||
abilities = """
|
||||
plan(task: str) -> typing.List[str]
|
||||
write_file(contents: str, filepath: str) -> bool
|
||||
read_file(filepath:str) -> typing.Optional[str]
|
||||
append_to_file(contents: str, filepath: str, to_start: bool) -> bool
|
||||
read_webpage(url: str) -> str
|
||||
write_file(contents='The content you want to write', filepath='file_to_write.txt')
|
||||
read_file(filepath='file_to_write.txt')
|
||||
"""
|
||||
json_format = """
|
||||
{
|
||||
"steps": [
|
||||
"write_file('The capital is xxx', 'answer.txt')",
|
||||
"read_file('file_to_read.txt')",
|
||||
"write_file(contents='The capital is xxx', filepath='answer.txt')",
|
||||
"read_file(filepath='file_to_read.txt')",
|
||||
]
|
||||
}
|
||||
"""
|
||||
planning_prompt = f"""Answer in json format:
|
||||
Determine the steps needed to complete the following task using only the defined list of steps with the parameters provided:
|
||||
Determine the steps needed to complete the following task :
|
||||
{task}
|
||||
---
|
||||
Possible steps
|
||||
Possible steps:
|
||||
{abilities}
|
||||
|
||||
---
|
||||
Example answer:
|
||||
{json_format}
|
||||
|
||||
---
|
||||
As you can see, we only use hard coded values when calling the functions.
|
||||
Please write your answer below:
|
||||
"""
|
||||
messages = [{"role": "user", "content": planning_prompt}]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user