Add SpecWriter agent (#657)

* Add SpecWriter agent

* pr feedback

* pr feedback 2
This commit is contained in:
Senko Rašić
2024-02-17 17:27:05 -08:00
committed by GitHub
parent 5492bc5189
commit 0e657379eb
9 changed files with 210 additions and 7 deletions

View File

@@ -24,13 +24,14 @@ class AgentConvo:
agent: An instance of the agent participating in the conversation.
"""
def __init__(self, agent):
def __init__(self, agent, temperature: float = 0.7):
# [{'role': 'system'|'user'|'assistant', 'content': ''}, ...]
self.messages: list[dict] = []
self.branches = {}
self.log_to_user = True
self.agent = agent
self.high_level_step = self.agent.project.current_step
self.temperature = temperature
# add system message
system_message = get_sys_message(self.agent.role, self.agent.project.args)
@@ -63,7 +64,8 @@ class AgentConvo:
try:
self.replace_files()
response = create_gpt_chat_completion(self.messages, self.high_level_step, self.agent.project,
function_calls=function_calls, prompt_data=prompt_data)
function_calls=function_calls, prompt_data=prompt_data,
temperature=self.temperature)
except TokenLimitError as e:
save_development_step(self.agent.project, prompt_path, prompt_data, self.messages, '', str(e))
raise e

View File

@@ -22,6 +22,7 @@ from helpers.agents.Developer import Developer
from helpers.agents.Architect import Architect
from helpers.agents.ProductOwner import ProductOwner
from helpers.agents.TechnicalWriter import TechnicalWriter
from helpers.agents.SpecWriter import SpecWriter
from database.models.development_steps import DevelopmentSteps
from database.models.file_snapshot import FileSnapshot
@@ -165,8 +166,9 @@ class Project:
return False
self.project_manager = ProductOwner(self)
self.project_manager.get_project_description()
self.spec_writer = SpecWriter(self)
self.project_manager.get_project_description(self.spec_writer)
self.project_manager.get_user_stories()
# self.user_tasks = self.project_manager.get_user_tasks()

View File

@@ -19,7 +19,7 @@ class ProductOwner(Agent):
def __init__(self, project):
super().__init__('product_owner', project)
def get_project_description(self):
def get_project_description(self, spec_writer):
print(json.dumps({
"project_stage": "project_description"
}), type='info')
@@ -72,7 +72,7 @@ class ProductOwner(Agent):
}}), type='info')
high_level_messages = []
high_level_summary = self.project.main_prompt
high_level_summary = spec_writer.create_spec(self.project.main_prompt)
save_progress(self.project.args['app_id'], self.project.current_step, {
"prompt": self.project.main_prompt,

View File

@@ -0,0 +1,98 @@
from helpers.AgentConvo import AgentConvo
from helpers.Agent import Agent
from utils.files import count_lines_of_code
from utils.style import color_green_bold, color_yellow_bold
from prompts.prompts import ask_user
from const.messages import AFFIRMATIVE_ANSWERS
from utils.exit import trace_code_event
INITIAL_PROJECT_HOWTO_URL = "https://github.com/Pythagora-io/gpt-pilot/wiki/How-to-write-a-good-initial-project-description"
class SpecWriter(Agent):
def __init__(self, project):
super().__init__('spec_writer', project)
self.save_dev_steps = True
def analyze_project(self, initial_prompt):
msg = (
"Your project description seems a bit short. "
"The better you can describe the project, the better GPT Pilot will understand what you'd like to build.\n\n"
f"Here are some tips on how to better describe the project: {INITIAL_PROJECT_HOWTO_URL}\n\n"
)
print(color_yellow_bold(msg))
print(color_green_bold("Let's start by refining your project idea:"))
convo = AgentConvo(self)
convo.construct_and_add_message_from_prompt('spec_writer/ask_questions.prompt', {})
num_questions = 0
skipped = False
user_response = initial_prompt
while True:
llm_response = convo.send_message('utils/python_string.prompt', {
"content": user_response,
})
if not llm_response:
continue
num_questions += 1
llm_response = llm_response.strip()
if len(llm_response) > 500:
print('continue', type='button')
user_response = ask_user(
self.project,
"Can we proceed with this project description? If so, just press ENTER. Otherwise, please tell me what's missing or what you'd like to add.",
hint="Does this sound good, and does it capture all the information about your project?",
require_some_input=False
)
if user_response:
user_response = user_response.strip()
if user_response.lower() in AFFIRMATIVE_ANSWERS + ['continue']:
break
else:
print('skip questions', type='button')
user_response = ask_user(self.project, llm_response)
if user_response and user_response.lower() == 'skip questions':
llm_response = convo.send_message(
'utils/python_string.prompt',
{
'content': 'This is enough clarification, you have all the information. Please output the spec now, without additional comments or questions.',
}
)
skipped = True
break
trace_code_event(
"spec-writer-questions",
{
"initial_prompt_length": len(initial_prompt),
"num_questions": num_questions,
"final_prompt_length": len(llm_response),
"skipped": skipped,
}
)
return llm_response
def review_spec(self, initial_prompt, spec):
convo = AgentConvo(self, temperature=0)
llm_response = convo.send_message('spec_writer/review_spec.prompt', {
"brief": initial_prompt,
"spec": spec,
})
if not llm_response:
return None
return llm_response.strip()
def create_spec(self, initial_prompt):
if len(initial_prompt) > 1500:
return initial_prompt
spec = self.analyze_project(initial_prompt)
missing_info = self.review_spec(initial_prompt, spec)
if missing_info:
spec += "\nAdditional info/examples:\n" + missing_info
return spec

View File

@@ -0,0 +1,76 @@
Your task is to talk to a new client and develop a detailed specification for a new application the client wants to build. This specification will serve as an input to an AI software developer and thus must be very detailed, contain all the project functionality and precisely define behaviour, 3rd-party integrations (if any), etc.
The AI developer prefers working on web apps using Node/Express/MongoDB/Mongoose/EJS stack, and use vanilla JS with Bootstrap on the frontend, unless the client has different requirements.
Try to avoid the use of Docker, Kubernetes, microservices and single-page app frameworks like React, Next.js, Angular, Vue or Svelte unless the brief explicitly requires it.
In your work, follow these important rules:
* In your communication with the client, be straightforward, concise, and focused on the task.
* Ask questions ONE BY ONE. This is veryy important, as the client is easily confused. If you were to ask multiple questions the user would probably miss some questions, so remember to always ask the questions one by one
* Ask specific questions, taking into account what you already know about the project. For example, don't ask "what features do you need?" or "describe your idea"; instead ask "what is the most important feature?"
* Pay special attention to any documentation or information that the project might require (such as accessing a custom API, etc). Be sure to ask the user to provide information and examples that the developers will need to build the proof-of-concept. You will need to output all of this in the final specification.
* This is a a prototype project, it is important to have small and well-defined scope. If the scope seems to grow too large (beyond a week or two of work for one developer), ask the user if they can simplify the project.
* Do not address non-functional requirements (performance, deployment, security, budget, timelines, etc...). We are only concerned with functional and technical specification here.
* Do not address deployment or hosting, including DevOps tasks to set up a CI/CD pipeline
* Don't address or invision any future development (post proof-of-concept), the scope of your task is to only spec the PoC/prototype.
* If the user provided specific information on how to access 3rd party API or how exactly to implement something, you MUST include that in the specification. Remember, the AI developer will only have access to the specification you write.
Ensure that you have all the information about:
* overall description and goals for the app
* all the features of the application
* functional specification
* how the user will use the app
* enumerate all the parts of the application (eg. pages of the application, background processing if any, etc); for each part, explain *in detail* how it should work from the perspective of the user
* identify any constraints, business rules, user flows or other important info that affect how the application works or how it is used
* technical specification
* what kind of an application this is and what platform/technologies will be used
* the architecture of the application (what happens on backend, frontend, mobile, background tasks, integration with 3rd party services, etc)
* detailed description of each component of the application architecture
* integration specification
* any 3rd party apps, services, APIs that will be used (eg. for auth, payments, etc..)
* if a custom API is used, precise definitions, with examples, how to use the custom API or do the custom integration
If you identify any missing information or need clarification on any vague or ambiguous parts of the brief, ask the client about it.
Important note: don't ask trivial questions for obvious or unimportant parts of the app, for example:
* Bad questions example 1:
* Client brief: I want to build a hello world web app
* Bad questions:
* What title do you want for the web page that displays "Hello World"?
* What color and font size would you like for the "Hello World" text to be displayed in?
* Should the "Hello World" message be static text served directly from the server, or would you like it implemented via JavaScript on the client side?
* Explanation: There's no need to micromanage the developer(s) and designer(s), the client would've specified these details if they were important.
If you ask such trivial questions, the client will think you're stupid and will leave. DOn'T DO THAT
Think carefully about what a developer must know to be able to build the app. The specification must address all of this information, otherwise the AI software developer will not be able to build the app.
When you gather all the information from the client, output the complete specification. Remember, the specification should define both functional aspects (features - what it does, what the user should be able to do), the technical details (architecture, technologies preferred by the user, etc), and the integration details (pay special attention to describe these in detail). Include all important features and clearly describe how each feature should function. IMPORTANT: Do not add any preamble (eg. "Here's the specification....") or conclusion/commentary (eg. "Let me know if you have further questions")!
Here's an EXAMPLE initial prompt:
---start-of-example-output---
Online forum similar to Hacker News (news.ycombinator.com), with a simple and clean interface, where people can post links or text posts, and other people can upvote, downvote and comment on. Reading is open to anonymous users, but users must register to post, upvote, downvote or comment. Use simple username+password authentication. The forum should be implemented in Node.js with Express framework, using MongoDB and Mongoose ORM.
The UI should use EJS view engine, Bootstrap for styling and plain vanilla JavaScript. Design should be simple and look like Hacker News, with a top bar for navigation, using a blue color scheme instead of the orange color in HN. The footer in each page should just be "Built using GPT Pilot".
Each story has a title (one-line text), a link (optional, URL to an external article being shared on AI News), and text (text to show in the post). Link and text are mutually exclusive - if the submitter tries to use both, show them an error.
Use the following algorithm to rank top stories, and comments within a story: "score = upvotes - downvotes + comments - sqrt(age)" , where "upvotes" and "downvotes" are the number of upvotes and downvotes the story or comment has, "comments" is the number of comments for a story (total), or the number of sub-comments (for a comment), and "age" is how old is the story, in minutes, and "sqrt" is the square root function.
Implement the following pages:
* / - shows the top 20 posted stories, ranked using the scoring algorithm, with a "More" link that shows the next 20 (pagination using "p" query parameter), and so on
* /newest - shows the latest 20 posted stories, ranked chronologically (newest first), with a "More" link that shows the next 20 (pagination using "p" query parameter), and so on
* /submit - shows a form to submit a new story, upon submitting the user should get redirected to /newest
* /login - shows a login form (username, password, "login" button, and a link to register page for new users)
* /register - shows a register form (username, password, "register" button, and a link to login page for existing users)
* /item - shows the story (use "id" query parameter to pass the story ID to this route)
* /comment - shows the form to send a comment (just a textarea and "submit" button) - upon commenting, the person should get redirected to the story they commented on
The / and /newest pages should show the story title (link to the external article if "link" is set, otherwise link to the story item /item page), number of points (points = upvotes - downvotes), poster username (no link), how old is the story ("x minutes ago", "y hours ago" or "z days ago"), and "xyz comments" (link to /item page of the story). This is basically the same how HN shows it.
The /item page should also follow the layout for HN in how it shows the story, and the comments tree. Instead of the embedded "reply" form, the story should just have a "comment" button that goes to the /comment page, similar to the "reply" link underneath each comment. Both should link to the /comment page.
---end-of-example-output---
Remember, this is important: the AI developer will not have access to client's initial description and transcript of your conversation. The developer will only see the specification you output on the end. It is very important that the spec captures *all* the details of the project in as much detail and precision as possible.
Note: after the client reads the specification you create, the client might have additional comments or suggestions. In this case, continue the discussion with the user until you get all the new information and output the newly updated spec again.

View File

@@ -0,0 +1,22 @@
Your team has taken the client brief and turned it into a project specification.
Your job is to check the specification and identify all the information that is contained in the client brief, but missing from the specification.
This might include:
* details on how the app should work
* information which 3rd party packages or APIs to use or avoid
* concrete examples of API requests/responses, library usage, or other external documentation
Here is the client brief:
---CLIENT-BRIEF-START---
{{ brief }}
---CLIENT-BRIEF-END---
Here is the specification your team came up with:
---SPEC-START---
{{ spec }}
---SPEC-END---
In your response, output all the information that is present in the client brief but missing from the spec, so it can be appended.
Note: don't output suggestion to your team to take back to the drawing board. Instead, just output the missing information and the team will append it to the generated spec. If there is no missing information, just output an empty response ('').

View File

@@ -0,0 +1 @@
You are a product owner working in a software development agency.

View File

@@ -0,0 +1 @@
{{ content }}

View File

@@ -92,7 +92,8 @@ def test_api_access(project) -> bool:
def create_gpt_chat_completion(messages: List[dict], req_type, project,
function_calls: FunctionCallSet = None,
prompt_data: dict = None):
prompt_data: dict = None,
temperature: float = 0.7):
"""
Called from:
- AgentConvo.send_message() - these calls often have `function_calls`, usually from `pilot/const/function_calls.py`
@@ -111,7 +112,7 @@ def create_gpt_chat_completion(messages: List[dict], req_type, project,
gpt_data = {
'model': os.getenv('MODEL_NAME', 'gpt-4'),
'n': 1,
'temperature': 0.7,
'temperature': temperature,
'top_p': 1,
'presence_penalty': 0,
'frequency_penalty': 0,