Skip to content
Merged

Dev #100

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
4289808
Add IssueRequest model to handle issue data in API
dcloud347 Aug 3, 2025
c83f10f
Fix formatting in issue.py by adding missing newline at end of file
dcloud347 Aug 3, 2025
1c5a274
Remove upload_local_repository endpoint from repository.py
dcloud347 Aug 3, 2025
1256c33
Add Settings class for configuration management using Pydantic
dcloud347 Aug 3, 2025
202c28c
Refactor config.py for improved formatting and readability
dcloud347 Aug 3, 2025
01b6530
Implement BaseService class and refactor service classes to inherit f…
dcloud347 Aug 3, 2025
e17a25c
Refactor service initialization to return a dictionary of services in…
dcloud347 Aug 3, 2025
5ecf4a1
Add GITHUB_ACCESS_TOKEN to configuration settings
dcloud347 Aug 3, 2025
385a9bb
Refactor GitHub repository upload functions to use service dictionary…
dcloud347 Aug 3, 2025
eba7732
Update working_directory type to string and ensure proper Path handli…
dcloud347 Aug 3, 2025
f51660c
Rename OPENAI_API_KEY to OPENAI_FORMAT_API_KEY and update example.env…
dcloud347 Aug 3, 2025
a1ae766
Refactor repository cloning functions for improved readability and co…
dcloud347 Aug 3, 2025
ea618a6
Add general settings to Docker Compose files and remove GitHub access…
dcloud347 Aug 3, 2025
41ef1d9
Refactor GitHub repository upload functions to use type hints and imp…
dcloud347 Aug 3, 2025
a8376ea
Refactor issue handling and repository deletion logic for improved cl…
dcloud347 Aug 3, 2025
870d1f8
Add logging for environment and CORS origins in main.py
dcloud347 Aug 3, 2025
c21d744
Add custom unique ID generation for API routes in FastAPI application
dcloud347 Aug 3, 2025
0fef3b8
Update API documentation to correct endpoint URL for issue answering
dcloud347 Aug 3, 2025
6df68b9
Add DatabaseService for database management and integrate into depend…
dcloud347 Aug 4, 2025
e512457
Add logging for Neo4j driver connection closure in Neo4jService
dcloud347 Aug 4, 2025
b1f42a6
Update user model field constraints for username, email, and github_t…
dcloud347 Aug 4, 2025
f18839e
Add UserService and user model for user management
dcloud347 Aug 4, 2025
971008f
Add start method to BaseService and DatabaseService for service initi…
dcloud347 Aug 4, 2025
0f41172
delete create_db_and_tables.py
dcloud347 Aug 4, 2025
b6a66a4
Add superuser creation functionality with email validation
dcloud347 Aug 4, 2025
2340393
Refactor user creation method documentation to include issue_credit p…
dcloud347 Aug 4, 2025
0e662b9
Replace bcrypt with argon2 for password hashing in user creation
dcloud347 Aug 4, 2025
4e1a117
Fix import path for FileOperationException and rename exception file
dcloud347 Aug 4, 2025
03b2f4f
Add JWT configuration settings to config and example.env
dcloud347 Aug 4, 2025
e14e7e5
Add JWTException and ServerException classes for error handling
dcloud347 Aug 4, 2025
c5d5a58
Add JWT utility class for token generation and validation
dcloud347 Aug 4, 2025
0ceb27d
Add script to generate secure JWT secret token and update README
dcloud347 Aug 4, 2025
b8214ae
Refactor JWTUtils to use double quotes for string literals and improv…
dcloud347 Aug 4, 2025
77f3418
Add authentication module with login request and response models
dcloud347 Aug 4, 2025
cbd7082
Add IssueResponse model and update answer_issue function to return st…
dcloud347 Aug 4, 2025
b36286c
Refactor upload_github_repository functions to raise ServerException …
dcloud347 Aug 4, 2025
8f87eda
Add global exception handlers for FastAPI application
dcloud347 Aug 4, 2025
2151208
add unified return json format
dcloud347 Aug 4, 2025
60e5787
Refactor authentication and repository endpoints to use a unified res…
dcloud347 Aug 4, 2025
c4b8c38
Refactor answer_issue function to use a generic Response model and ra…
dcloud347 Aug 4, 2025
0b09e9d
Update test fixtures to use a consistent working directory path
dcloud347 Aug 4, 2025
6179b27
Remove unused test functions for local repository uploads
dcloud347 Aug 4, 2025
0d79e8c
Normalize success message to lowercase in response model
dcloud347 Aug 4, 2025
9351c63
Refactor test files to use a unified mock service structure and regis…
dcloud347 Aug 4, 2025
e7f9396
Fix formatting issue in test_issue.py by correcting indentation
dcloud347 Aug 4, 2025
d2eed58
Add database service tests and remove redundant port binding in fixtures
dcloud347 Aug 4, 2025
3b4a38a
Refactor postgres container fixture for improved readability
dcloud347 Aug 4, 2025
04a0269
Update test_issue_service.py to modify working directory path and adj…
dcloud347 Aug 4, 2025
a26660f
Update environment configuration for CORS and add JWT secret key
dcloud347 Aug 4, 2025
ce00bd8
Add user service tests for superuser creation
dcloud347 Aug 4, 2025
1726289
Refactor superuser creation test for improved readability
dcloud347 Aug 4, 2025
a773c2c
Refactor mock_database_service fixture to use yield for resource mana…
dcloud347 Aug 4, 2025
63e2ce1
Add login test and refactor user retrieval queries in UserService
dcloud347 Aug 4, 2025
9bdf3a6
Refactor email validation method to use class method syntax
dcloud347 Aug 4, 2025
439a9e8
Add unit tests for authentication login endpoint
dcloud347 Aug 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/pytest_and_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ jobs:
# Logging
PROMETHEUS_LOGGING_LEVEL: DEBUG

# General settings
PROMETHEUS_ENVIRONMENT: local
PROMETHEUS_BACKEND_CORS_ORIGINS: "[\"*\"]"

# Neo4j settings
PROMETHEUS_NEO4J_URI: bolt://localhost:7687
PROMETHEUS_NEO4J_USERNAME: neo4j
Expand Down Expand Up @@ -48,6 +52,9 @@ jobs:
# DATABASE settings
PROMETHEUS_DATABASE_URL: postgresql://postgres:password@localhost:5432/postgres?sslmode=disable

# JWT settings
PROMETHEUS_JWT_SECRET_KEY: your_jwt_secret_key

steps:
- name: Check out code
uses: actions/checkout@v4
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,20 @@ governed by a state machine to ensure code quality through automated reviews, bu
```

2. #### Copy the `example.env` file to `.env` and update it with your API keys and other required configurations:

```bash
mv example.env .env
```

> You need to provide a secure `JWT_SECRET_KEY` in the `.env` file.
> You can generate a strong key by running the following command:

```bash
python -m prometheus.script.generate_jwt_token
```

This will print a secure token you can copy and paste into your `.env` file

3. #### Create the working directory to store logs and cloned repositories:

```bash
Expand Down Expand Up @@ -124,7 +134,7 @@ governed by a state machine to ensure code quality through automated reviews, bu
You can ask Prometheus to analyze and answer a specific issue in your codebase using the `/issue/answer/` API endpoint.

- **Endpoint:** `POST /issue/answer/`
- **Request Body:** JSON object matching the `IssueRequest` schema (see [API Documents](http://localhost:9002/docs#/issue/answer_issue_issue_answer__post))
- **Request Body:** JSON object matching the `IssueRequest` schema (see [API Documents](http://127.0.0.1:9002/docs#/issue/issue-answer_issue))
- **Response:** Returns the generated patch, test/build results, and a summary response.

---
Expand Down
7 changes: 4 additions & 3 deletions docker-compose.win_mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ services:
# Logging
- PROMETHEUS_LOGGING_LEVEL=${PROMETHEUS_LOGGING_LEVEL}

# General settings
- PROMETHEUS_ENVIRONMENT=${PROMETHEUS_ENVIRONMENT}
- PROMETHEUS_BACKEND_CORS_ORIGINS=${PROMETHEUS_BACKEND_CORS_ORIGINS}

# Neo4j settings
- PROMETHEUS_NEO4J_URI=${PROMETHEUS_NEO4J_URI}
- PROMETHEUS_NEO4J_USERNAME=${PROMETHEUS_NEO4J_USERNAME}
Expand Down Expand Up @@ -64,9 +68,6 @@ services:
- PROMETHEUS_MAX_OUTPUT_TOKENS=${PROMETHEUS_MAX_OUTPUT_TOKENS}
- PROMETHEUS_TEMPERATURE=${PROMETHEUS_TEMPERATURE}

# GitHub settings
- PROMETHEUS_GITHUB_ACCESS_TOKEN=${PROMETHEUS_GITHUB_ACCESS_TOKEN}

# Database settings
- PROMETHEUS_DATABASE_URL=${PROMETHEUS_DATABASE_URL}
networks:
Expand Down
7 changes: 4 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ services:
# Logging
- PROMETHEUS_LOGGING_LEVEL=${PROMETHEUS_LOGGING_LEVEL}

# General settings
- PROMETHEUS_ENVIRONMENT=${PROMETHEUS_ENVIRONMENT}
- PROMETHEUS_BACKEND_CORS_ORIGINS=${PROMETHEUS_BACKEND_CORS_ORIGINS}

# Neo4j settings
- PROMETHEUS_NEO4J_URI=${PROMETHEUS_NEO4J_URI}
- PROMETHEUS_NEO4J_USERNAME=${PROMETHEUS_NEO4J_USERNAME}
Expand Down Expand Up @@ -85,9 +89,6 @@ services:
- PROMETHEUS_MAX_OUTPUT_TOKENS=${PROMETHEUS_MAX_OUTPUT_TOKENS}
- PROMETHEUS_TEMPERATURE=${PROMETHEUS_TEMPERATURE}

# GitHub settings
- PROMETHEUS_GITHUB_ACCESS_TOKEN=${PROMETHEUS_GITHUB_ACCESS_TOKEN}

# Database settings
- PROMETHEUS_DATABASE_URL=${PROMETHEUS_DATABASE_URL}
volumes:
Expand Down
10 changes: 7 additions & 3 deletions example.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Logging
PROMETHEUS_LOGGING_LEVEL=DEBUG

# General settings
PROMETHEUS_ENVIRONMENT=local
PROMETHEUS_BACKEND_CORS_ORIGINS=["*]

# Neo4j settings
PROMETHEUS_NEO4J_URI=bolt://neo4j:7687
PROMETHEUS_NEO4J_USERNAME=neo4j
Expand Down Expand Up @@ -29,8 +33,8 @@ PROMETHEUS_MAX_INPUT_TOKENS=64000
PROMETHEUS_TEMPERATURE=0.3
PROMETHEUS_MAX_OUTPUT_TOKENS=15000

# GitHub settings
PROMETHEUS_GITHUB_ACCESS_TOKEN=github_access_token

# Database settings
PROMETHEUS_DATABASE_URL=postgresql://postgres:password@localhost:5432/postgres?sslmode=disable

# JWT settings
PROMETHEUS_JWT_SECRET_KEY=your_jwt_secret_key
30 changes: 30 additions & 0 deletions prometheus/app/api/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from fastapi import APIRouter, Request

from prometheus.app.models.requests.auth import LoginRequest
from prometheus.app.models.response.auth import LoginResponse
from prometheus.app.models.response.response import Response
from prometheus.app.services.user_service import UserService

router = APIRouter()


@router.post(
"/login/",
summary="Login to the system",
description="Login to the system using username, email, and password. Returns an access token.",
response_description="Returns an access token for authenticated requests",
response_model=Response[LoginResponse],
)
def login(login_request: LoginRequest, request: Request) -> Response[LoginResponse]:
"""
Login to the system using username, email, and password.
Returns an access token for authenticated requests.
"""

user_service: UserService = request.app.state.service["user_service"]
access_token = user_service.login(
username=login_request.username,
email=login_request.email,
password=login_request.password,
)
return Response(data=LoginResponse(access_token=access_token))
124 changes: 27 additions & 97 deletions prometheus/app/api/issue.py
Original file line number Diff line number Diff line change
@@ -1,105 +1,33 @@
from typing import Mapping, Optional, Sequence
from fastapi import APIRouter, Request

from fastapi import APIRouter, HTTPException, Request
from litellm import Field
from pydantic import BaseModel

from prometheus.lang_graph.graphs.issue_state import IssueType
from prometheus.app.models.requests.issue import IssueRequest
from prometheus.app.models.response.issue import IssueResponse
from prometheus.app.models.response.response import Response
from prometheus.exceptions.server_exception import ServerException

router = APIRouter()


class IssueRequest(BaseModel):
issue_number: int = Field(description="The number of the issue", examples=[42])
issue_title: str = Field(
description="The title of the issue", examples=["There is a memory leak"]
)
issue_body: str = Field(
description="The description of the issue", examples=["foo/bar.c is causing a memory leak"]
)
issue_comments: Optional[Sequence[Mapping[str, str]]] = Field(
default=None,
description="Comments on the issue",
examples=[
[
{"username": "user1", "comment": "I've experienced this issue as well."},
{
"username": "user2",
"comment": "A potential fix is to adjust the memory settings.",
},
]
],
)
issue_type: IssueType = Field(
default=IssueType.AUTO,
description="The type of the issue, set to auto if you do not know",
examples=[IssueType.AUTO],
)
run_build: Optional[bool] = Field(
default=False,
description="When editing the code, whenver we should run the build to verify the fix",
examples=[False],
)
run_existing_test: Optional[bool] = Field(
default=False,
description="When editing the code, whenver we should run the existing test to verify the fix",
examples=[False],
)
number_of_candidate_patch: Optional[int] = Field(
default=4,
description="When the patch is not verfied (through build or test), number of candidate patches we generate to select the best one",
examples=[4],
)
dockerfile_content: Optional[str] = Field(
default=None,
description="Specify the containerized environment with dockerfile content",
examples=["FROM python:3.11\nWORKDIR /app\nCOPY . /app"],
)
image_name: Optional[str] = Field(
default=None,
description="Specify the containerized environment with image name that should be pulled from dockerhub",
examples=["python:3.11-slim"],
)
workdir: Optional[str] = Field(
default=None,
description="If you specified the container environment, you must also specify the workdir",
examples=["/app"],
)
build_commands: Optional[Sequence[str]] = Field(
default=None,
description="If you specified dockerfile_content and run_build is True, you must also specify the build commands.",
examples=[["pip install -r requirements.txt", "python -m build"]],
)
test_commands: Optional[Sequence[str]] = Field(
default=None,
description="If you specified dockerfile_content and run_test is True, you must also specify the test commands.",
examples=[["pytest ."]],
)
push_to_remote: Optional[bool] = Field(
default=False,
description="When editing the code, whenver we should push the changes to a remote branch",
examples=[True],
)


@router.post(
"/answer/",
summary="Process and generate a response for an issue",
description="Analyzes an issue, generates patches if needed, runs optional builds and tests, and can push changes to a remote branch.",
description="Analyzes an issue, generates patches if needed, runs optional builds and tests, and can push changes "
"to a remote branch.",
response_description="Returns the patch, test results, and issue response",
response_model=Response[IssueResponse],
)
def answer_issue(issue: IssueRequest, request: Request):
if not request.app.state.service_coordinator.exists_knowledge_graph():
raise HTTPException(
status_code=404,
detail="A repository is not uploaded, use /repository/ endpoint to upload one",
def answer_issue(issue: IssueRequest, request: Request) -> Response[IssueResponse]:
if not request.app.state.service["knowledge_graph_service"].exists():
raise ServerException(
code=404,
message="A repository is not uploaded, use /repository/ endpoint to upload one",
)

if issue.dockerfile_content or issue.image_name:
if issue.workdir is None:
raise HTTPException(
status_code=400,
detail="workdir must be provided for user defined environment",
raise ServerException(
code=400,
message="workdir must be provided for user defined environment",
)

(
Expand All @@ -109,7 +37,7 @@ def answer_issue(issue: IssueRequest, request: Request):
passed_build,
passed_existing_test,
issue_response,
) = request.app.state.service_coordinator.answer_issue(
) = request.app.state.service["issue_service"].answer_issue(
issue_number=issue.issue_number,
issue_title=issue.issue_title,
issue_body=issue.issue_body,
Expand All @@ -125,11 +53,13 @@ def answer_issue(issue: IssueRequest, request: Request):
test_commands=issue.test_commands,
push_to_remote=issue.push_to_remote,
)
return {
"patch": patch,
"passed_reproducing_test": passed_reproducing_test,
"passed_build": passed_build,
"passed_existing_test": passed_existing_test,
"issue_response": issue_response,
"remote_branch_name": remote_branch_name,
}
return Response(
data=IssueResponse(
patch=patch,
passed_reproducing_test=passed_reproducing_test,
passed_build=passed_build,
passed_existing_test=passed_existing_test,
issue_response=issue_response,
remote_branch_name=remote_branch_name,
)
)
Loading