Full Code of AntonOsika/gpt-engineer for AI

main a90fcd543eed cached
177 files
676.2 KB
169.3k tokens
417 symbols
1 requests
Download .txt
Showing preview only (723K chars total). Download the full file or copy to clipboard to get everything.
Repository: AntonOsika/gpt-engineer
Branch: main
Commit: a90fcd543eed
Files: 177
Total size: 676.2 KB

Directory structure:
gitextract_dhh25wks/

├── .dockerignore
├── .github/
│   ├── CODEOWNERS
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   ├── documentation-clarification.md
│   │   └── feature-request.md
│   ├── PULL_REQUEST_TEMPLATE/
│   │   └── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── automation.yml
│       ├── ci.yaml
│       ├── pre-commit.yaml
│       └── release.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── Acknowledgements.md
├── DISCLAIMER.md
├── GOVERNANCE.md
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── ROADMAP.md
├── TERMS_OF_USE.md
├── WINDOWS_README.md
├── citation.cff
├── docker/
│   ├── Dockerfile
│   ├── README.md
│   └── entrypoint.sh
├── docker-compose.yml
├── docs/
│   ├── Makefile
│   ├── api_reference.rst
│   ├── code_conduct_link.rst
│   ├── conf.py
│   ├── contributing_link.rst
│   ├── create_api_rst.py
│   ├── disclaimer_link.rst
│   ├── docs_building.md
│   ├── examples/
│   │   └── open_llms/
│   │       ├── README.md
│   │       ├── langchain_interface.py
│   │       └── openai_api_interface.py
│   ├── index.rst
│   ├── installation.rst
│   ├── introduction.md
│   ├── make.bat
│   ├── open_models.md
│   ├── quickstart.rst
│   ├── roadmap_link.rst
│   ├── terms_link.rst
│   ├── tracing_debugging.md
│   └── windows_readme_link.rst
├── gpt_engineer/
│   ├── __init__.py
│   ├── applications/
│   │   ├── __init__.py
│   │   └── cli/
│   │       ├── __init__.py
│   │       ├── cli_agent.py
│   │       ├── collect.py
│   │       ├── file_selector.py
│   │       ├── learning.py
│   │       └── main.py
│   ├── benchmark/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── bench_config.py
│   │   ├── benchmarks/
│   │   │   ├── apps/
│   │   │   │   ├── load.py
│   │   │   │   ├── problem.py
│   │   │   │   └── problems.py
│   │   │   ├── gptme/
│   │   │   │   └── load.py
│   │   │   ├── load.py
│   │   │   └── mbpp/
│   │   │       ├── load.py
│   │   │       ├── problem.py
│   │   │       └── problems.py
│   │   ├── default_bench_config.toml
│   │   ├── run.py
│   │   └── types.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── ai.py
│   │   ├── base_agent.py
│   │   ├── base_execution_env.py
│   │   ├── base_memory.py
│   │   ├── chat_to_files.py
│   │   ├── default/
│   │   │   ├── __init__.py
│   │   │   ├── constants.py
│   │   │   ├── disk_execution_env.py
│   │   │   ├── disk_memory.py
│   │   │   ├── file_store.py
│   │   │   ├── paths.py
│   │   │   ├── simple_agent.py
│   │   │   └── steps.py
│   │   ├── diff.py
│   │   ├── files_dict.py
│   │   ├── git.py
│   │   ├── linting.py
│   │   ├── preprompts_holder.py
│   │   ├── project_config.py
│   │   ├── prompt.py
│   │   ├── token_usage.py
│   │   └── version_manager.py
│   ├── preprompts/
│   │   ├── clarify
│   │   ├── entrypoint
│   │   ├── file_format
│   │   ├── file_format_diff
│   │   ├── file_format_fix
│   │   ├── generate
│   │   ├── improve
│   │   ├── philosophy
│   │   └── roadmap
│   └── tools/
│       ├── __init__.py
│       ├── custom_steps.py
│       └── supported_languages.py
├── projects/
│   ├── example-improve/
│   │   ├── README.md
│   │   ├── controller.py
│   │   ├── main.py
│   │   ├── model.py
│   │   ├── prompt
│   │   ├── requirements.txt
│   │   ├── run.sh
│   │   └── view.py
│   └── example-vision/
│       ├── navigation.html
│       └── prompt
├── pyproject.toml
├── scripts/
│   ├── clean_benchmarks.py
│   ├── legacy_benchmark.py
│   ├── print_chat.py
│   └── test_api.py
├── sweep.yaml
├── tests/
│   ├── __init__.py
│   ├── ai_cache.json
│   ├── applications/
│   │   ├── __init__.py
│   │   └── cli/
│   │       ├── __init__.py
│   │       ├── test_cli_agent.py
│   │       ├── test_collect.py
│   │       ├── test_collection_consent.py
│   │       ├── test_learning.py
│   │       └── test_main.py
│   ├── benchmark/
│   │   └── test_BenchConfig.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── default/
│   │   │   ├── __init__.py
│   │   │   ├── test_disk_execution_env.py
│   │   │   ├── test_disk_file_repository.py
│   │   │   ├── test_simple_agent.py
│   │   │   └── test_steps.py
│   │   ├── improve_function_test_cases/
│   │   │   ├── apps_benchmark_6_chat
│   │   │   ├── apps_benchmark_6_code
│   │   │   ├── apps_benchmark_6_v2_chat
│   │   │   ├── apps_benchmark_6_v2_code
│   │   │   ├── controller_chat
│   │   │   ├── controller_code
│   │   │   ├── corrected_diff_from_missing_lines
│   │   │   ├── create_two_new_files_chat
│   │   │   ├── create_two_new_files_code
│   │   │   ├── simple_calculator_chat
│   │   │   ├── simple_calculator_code
│   │   │   ├── task_master_chat
│   │   │   ├── task_master_code
│   │   │   ├── temperature_converter_chat
│   │   │   ├── temperature_converter_code
│   │   │   ├── theo_case_chat
│   │   │   ├── theo_case_code
│   │   │   ├── vgvishesh_example_2_chat
│   │   │   ├── vgvishesh_example_2_code
│   │   │   ├── vgvishesh_example_chat
│   │   │   ├── vgvishesh_example_code
│   │   │   ├── wheaties_example_chat
│   │   │   ├── wheaties_example_code
│   │   │   ├── zbf_yml_missing_chat
│   │   │   └── zbf_yml_missing_code
│   │   ├── test_ai.py
│   │   ├── test_chat_to_files.py
│   │   ├── test_file_selector_enhancements.py
│   │   ├── test_git.py
│   │   ├── test_salvage_correct_hunks.py
│   │   └── test_token_usage.py
│   ├── mock_ai.py
│   ├── test_install.py
│   ├── test_project_config.py
│   └── tools/
│       └── example_snake_files.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Distribution / packaging
dist/
build/
*.egg-info/
*.egg

# Virtual environments
.env
.env.sh
venv/
ENV/

# IDE-specific files
.vscode/
.idea/

# Compiled Python modules
*.pyc
*.pyo
*.pyd

# Python testing
.pytest_cache/
.ruff_cache/
.coverage
.mypy_cache/

# macOS specific files
.DS_Store

# Windows specific files
Thumbs.db

# this application's specific files
archive

# any log file
*log.txt
todo
scratchpad

# Ignore GPT Engineer files
projects
!projects/example

# Pyenv
.python-version

# Benchmark files
benchmark
!benchmark/*/prompt

.gpte_consent


================================================
FILE: .github/CODEOWNERS
================================================
.github/workflows/ @ATheorell


================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity or expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
  community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or advances of
  any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
  without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting using an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<anton.osika@gmail.com>.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of reporters of incidents.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series of
actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within the
community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].

Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].

For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].

[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations


================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to gpt-engineer

The gpt-engineer is a community project and lives from your contributions - they are warmly appreciated. The main contribution avenues are:
- Pull request: implement code and have it reviewed and potentially merged by the maintainers. Implementations of existing feature requests or fixes to bug reports are likely to be merged.
- Bug report: report when something in gpt-engineer doesn't work. Do not report errors in programs written _by_ gpt-engineer.
- Feature request: provide a detailed sketch about something you want to have implemented in gpt-engineer. There is no guarantee that features will be implemented.
- Discussion: raise awareness of a potential improvement. This is often a good starting point before making a detailed feature request.

By participating in this project, you agree to abide by the [code of conduct](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/.github/CODE_OF_CONDUCT.md).

## Merge Policy for Pull Requests
Code that is likely to introduce breaking changes, or significantly change the user experience for users and developers, require [board approval](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/GOVERNANCE.md) to be merged. Smaller code changes can be merged directly.
As a rule, cosmetic pull requests, for example rephrasing the readme or introducing more compact syntax, that do not yield clear practical improvements are not merged. Such pull requests are generally discouraged, both to save time for the maintainers and to establish a lower bar for becoming a contributor.

## Getting Started with Pull Requests to gpt-engineer

To get started with contributing, please follow these steps:

1. Fork the repository and clone it to your local machine.
2. Install any necessary dependencies.
3. Create a new branch for your changes: `git checkout -b my-branch-name`.
4. Make your desired changes or additions.
5. Run the tests to ensure everything is working as expected.
6. Commit your changes: `git commit -m "Descriptive commit message"`.
7. Push to the branch: `git push origin my-branch-name`.
8. Submit a pull request to the `main` branch of the original repository.

## Code Style

Please make sure to follow the established code style guidelines for this project. Consistent code style helps maintain readability and makes it easier for others to contribute to the project.

To enforce this we use [`pre-commit`](https://pre-commit.com/) to run [`black`](https://black.readthedocs.io/en/stable/index.html) and [`ruff`](https://beta.ruff.rs/docs/) on every commit.

To install gpt-engineer as a developer, clone the repository and install the dependencies with:

```bash
$ poetry install
$ poetry shell
```

And then install the `pre-commit` hooks with:

```bash
$ pre-commit install

# output:
pre-commit installed at .git/hooks/pre-commit
```

If you are not familiar with the concept of [git hooks](https://git-scm.com/docs/githooks) and/or [`pre-commit`](https://pre-commit.com/) please read the documentation to understand how they work.

As an introduction of the actual workflow, here is an example of the process you will encounter when you make a commit:

Let's add a file we have modified with some errors, see how the pre-commit hooks run `black` and fails.
`black` is set to automatically fix the issues it finds:

```bash
$ git add chat_to_files.py
$ git commit -m "commit message"
black....................................................................Failed
- hook id: black
- files were modified by this hook

reformatted chat_to_files.py

All done! ✨ 🍰 ✨
1 file reformatted.
```

You can see that `chat_to_files.py` is both staged and not staged for commit. This is because `black` has formatted it and now it is different from the version you have in your working directory. To fix this you can simply run `git add chat_to_files.py` again and now you can commit your changes.

```bash
$ git status
On branch pre-commit-setup
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   chat_to_files.py

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   chat_to_files.py
```

Now let's add the file again to include the latest commits and see how `ruff` fails.

```bash
$ git add chat_to_files.py
$ git commit -m "commit message"
black....................................................................Passed
ruff.....................................................................Failed
- hook id: ruff
- exit code: 1
- files were modified by this hook

Found 2 errors (2 fixed, 0 remaining).
```

Same as before, you can see that `chat_to_files.py` is both staged and not staged for commit. This is because `ruff` has formatted it and now it is different from the version you have in your working directory. To fix this you can simply run `git add chat_to_files.py` again and now you can commit your changes.

```bash
$ git add chat_to_files.py
$ git commit -m "commit message"
black....................................................................Passed
ruff.....................................................................Passed
fix end of files.........................................................Passed
[pre-commit-setup f00c0ce] testing
 1 file changed, 1 insertion(+), 1 deletion(-)
```

Now your file has been committed and you can push your changes.

At the beginning this might seem like a tedious process (having to add the file again after `black` and `ruff` have modified it) but it is actually very useful. It allows you to see what changes `black` and `ruff` have made to your files and make sure that they are correct before you commit them.

### Important Note When `pre-commit` Fails in the Build Pipeline
Sometimes `pre-commit` will seemingly run successfully, as follows:

```bash
black................................................(no files to check)Skipped
ruff.................................................(no files to check)Skipped
check toml...........................................(no files to check)Skipped
check yaml...........................................(no files to check)Skipped
detect private key...................................(no files to check)Skipped
fix end of files.....................................(no files to check)Skipped
trim trailing whitespace.............................(no files to check)Skipped
```

However, you may see `pre-commit` fail in the build pipeline upon submitting a PR.  The solution to this is to run `pre-commit run --all-files` to force `pre-commit` to execute these checks, and make any necessary file modifications, to all files.


## Licensing

By contributing to gpt-engineer, you agree that your contributions will be licensed under the [LICENSE](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/LICENSE) file of the project.

Thank you for your interest in contributing to gpt-engineer! We appreciate your support and look forward to your contributions.


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [antonosika]
patreon: gpt_eng


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug, triage
assignees: ''

---

## Policy and info
 - Maintainers will close issues that have been stale for 14 days if they contain relevant answers.
 - Adding the label "sweep" will automatically turn the issue into a coded pull request. Works best for mechanical tasks. More info/syntax at: https://docs.sweep.dev/

## Expected Behavior

Please describe the behavior you are expecting.

## Current Behavior

What is the current behavior?

## Failure Information

Information about the failure, including environment details, such as LLM used.

### Failure Logs

If your project includes a debug_log_file.txt, kindly upload it from your_project/.gpteng/memory/ directory. This file encompasses all the necessary logs. Should the file prove extensive, consider utilizing GitHub's "add files" functionality.

## System Information

Please copy and paste the output of the `gpte --sysinfo` command as part of your bug report.

## Installation Method

Please specify whether you installed GPT-Engineer using `pip install` or by building the repository.


================================================
FILE: .github/ISSUE_TEMPLATE/documentation-clarification.md
================================================
---
name: Documentation improvement
about: Inaccuracies, inadequacies in the docs pages
title: ''
labels: documentation, triage
assignees: ''

---

## Policy and info
 - Maintainers will close issues that have been stale for 14 days if they contain relevant answers.
 - Adding the label "sweep" will automatically turn the issue into a coded pull request. Works best for mechanical tasks. More info/syntax at: https://docs.sweep.dev/


## Description
A clear and concise description of how the documentation at https://gpt-engineer.readthedocs.io/en/latest/ is providing wrong/insufficient information.

## Suggestion
How can it be improved


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement, triage
assignees: ''

---

## Policy and info
 - Maintainers will close issues that have been stale for 14 days if they contain relevant answers.
 - Adding the label "sweep" will automatically turn the issue into a coded pull request. Works best for mechanical tasks. More info/syntax at: https://docs.sweep.dev/
 - Consider adding the label "good first issue" for interesting, but easy features.

## Feature description
A clear and concise description of what you would like to have

## Motivation/Application
Why is this feature useful?


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/PULL_REQUEST_TEMPLATE.md
================================================
**YOU MAY DELETE THE ENTIRE TEMPLATE BELOW.**

## How Has This Been Tested?

Please describe if you have either:

- Generated the "example" project
- Ran the entire benchmark suite
- Something else


================================================
FILE: .github/workflows/automation.yml
================================================
name: Automation Workflow

on:
  schedule:
    - cron: '0 0 * * *'
  issues:
    types: [opened, edited, reopened]
  pull_request:
    types: [opened, edited, reopened]

jobs:
  mark-stale-issues:
    runs-on: ubuntu-latest
    steps:
      - name: Mark stale issues
        uses: actions/stale@v4
        with:
          stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.'
          days-before-stale: 60

  # Add additional jobs as needed
  # job-name:
  #   runs-on: ubuntu-latest
  #   steps:
  #     - name: Job step name
  #       uses: action-name@version
  #       with:
  #         parameter1: value1
  #


================================================
FILE: .github/workflows/ci.yaml
================================================
name: Tox pytest all python versions

on:
  push:
    branches: [ main ]
    paths:
      - gpt_engineer/**
      - tests/**
  pull_request:
    branches: [ main ]

concurrency:
  group: ${{ github.workflow }} - ${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']

    steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version == '3.12' && '3.12.3' || matrix.python-version }} # Using 3.12.3 to resolve Pydantic ForwardRef issue
        cache: 'pip'  # Note that pip is for the tox level. Poetry is still used for installing the specific environments (tox.ini)

    - name: Check Python Version
      run: python --version

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install tox==4.15.0 poetry

    - name: Run tox
      env:
        OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      run: tox

    # Temporarily disabling codecov until we resolve codecov rate limiting issue
    # - name: Report coverage
    #   run: |
    #     bash <(curl -s https://codecov.io/bash)


================================================
FILE: .github/workflows/pre-commit.yaml
================================================
name: pre-commit

on:
  pull_request:
  push:
    branches: [main]

jobs:
  pre-commit:
    runs-on: ubuntu-latest

    permissions:
      contents: write

    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-python@v4

      - uses: pre-commit/action@v3.0.0
        with:
          extra_args: --all-files


================================================
FILE: .github/workflows/release.yaml
================================================
name: Build and publish Python packages to PyPI

on:
  workflow_dispatch:
  release:
    types:
      - published

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
          # Removed the cache line that was here

      # Install Poetry
      - name: Install Poetry
        run: |
          curl -sSL https://install.python-poetry.org | python3 -

      # Add Poetry to PATH
      - name: Add Poetry to PATH
        run: echo "$HOME/.local/bin" >> $GITHUB_PATH

      # Cache Poetry's dependencies based on the lock file
      - name: Set up Poetry cache
        uses: actions/cache@v3
        with:
          path: ~/.cache/pypoetry
          key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
          restore-keys: |
            ${{ runner.os }}-poetry-

      # Install dependencies using Poetry (if any)
      - name: Install dependencies
        run: poetry install

      # Build package using Poetry
      - name: Build package
        run: poetry build --format sdist

      # Upload package as build artifact
      - uses: actions/upload-artifact@v3
        with:
          name: package
          path: dist/

  publish:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: pypi
      url: https://pypi.org/p/gpt-engineer
    permissions:
      id-token: write
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: package
          path: dist/

      - name: Publish packages to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
.history/

# Distribution / packaging
dist/
build/
*.egg-info/
*.egg

# Virtual environments
.env
.env.sh
venv/
ENV/
venv_test_installation/

# IDE-specific files
.vscode/
.idea/

# Compiled Python modules
*.pyc
*.pyo
*.pyd

# Python testing
.pytest_cache/
.ruff_cache/
.mypy_cache/
.coverage
coverage.*

# macOS specific files
.DS_Store

# Windows specific files
Thumbs.db

# this application's specific files
archive

# any log file
*log.txt
todo
scratchpad

# Pyenv
.python-version

.gpte_consent

# projects folder apart from default prompt

projects/*
!projects/example/prompt
!projects/example-improve
!projects/example-vision

# docs

docs/_build
docs/applications
docs/benchmark
docs/cli
docs/core
docs/intro
docs/tools

# coding assistants
.aider*
.gpteng

# webapp specific
webapp/node_modules
webapp/package-lock.json

webapp/.next/

.langchain.db

# TODO files
/!todo*

#ignore tox files
.tox

# locally saved datasets
gpt_engineer/benchmark/benchmarks/apps/dataset
gpt_engineer/benchmark/benchmarks/mbpp/dataset

gpt_engineer/benchmark/minimal_bench_config.toml

test.json


================================================
FILE: .pre-commit-config.yaml
================================================
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
fail_fast: true
default_stages: [commit]

repos:
  - repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
      - id: black
        args: [--config, pyproject.toml]
        types: [python]

  - repo: https://github.com/charliermarsh/ruff-pre-commit
    rev: "v0.0.272"
    hooks:
      - id: ruff
        args: [--fix, --exit-non-zero-on-fix]

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: check-toml
      - id: check-yaml
      - id: detect-private-key
      - id: end-of-file-fixer
      - id: trailing-whitespace


================================================
FILE: .readthedocs.yaml
================================================
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version and other tools you might need
build:
  os: ubuntu-22.04
  tools:
    python: "3.11"
    # You can also specify other tool versions:
    # nodejs: "19"
    # rust: "1.64"
    # golang: "1.19"
  jobs:
    post_create_environment:
      - pip install poetry
    post_install:
      - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs
    pre_build:
      - python docs/create_api_rst.py

# Build documentation in the "docs/" directory with Sphinx
sphinx:
   configuration: docs/conf.py

# Optionally build your docs in additional formats such as PDF and ePub
# formats:
#    - pdf
#    - epub

# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
#python:
#   install:
#   - requirements: docs/requirements.txt


================================================
FILE: Acknowledgements.md
================================================
# We thank the following people for inspiration

| Person | Content | File(s) | Source |
|----|---|---|---|
| Paul Gauthier | The prompt for the `improve code` step is strongly based on Paul's prompt in Aider | /preprompts/improve.txt | https://github.com/paul-gauthier/aider/blob/main/aider/coders/editblock_coder.py


================================================
FILE: DISCLAIMER.md
================================================
# Disclaimer

gpt-engineer is an experimental application and is provided "as-is" without any warranty, express or implied. By using this software, you agree to assume all risks associated with its use, including but not limited to data loss, system failure, or any other issues that may arise.

The developers and contributors of this project do not accept any responsibility or liability for any losses, damages, or other consequences that may occur as a result of using this software. You are solely responsible for any decisions and actions taken based on the information provided by gpt-engineer.

Please note that the use of the GPT-4 language model can be expensive due to its token usage. By utilizing this project, you acknowledge that you are responsible for monitoring and managing your own token usage and the associated costs. It is highly recommended to check your OpenAI API usage regularly and set up any necessary limits or alerts to prevent unexpected charges.

As an autonomous experiment, gpt-engineer may generate code or take actions that are not in line with real-world business practices or legal requirements. It is your responsibility to ensure that any actions or decisions made by the generated code comply with all applicable laws, regulations, and ethical standards. The developers and contributors of this project shall not be held responsible for any consequences arising from the use of this software.

By using gpt-engineer, you agree to indemnify, defend, and hold harmless the developers, contributors, and any affiliated parties from and against any and all claims, damages, losses, liabilities, costs, and expenses (including reasonable attorneys' fees) arising from your use of this software or your violation of these terms.


================================================
FILE: GOVERNANCE.md
================================================
# Governance Model of GPT-Engineer

## I. Project Board Structure

### Project Board

The Project Board is the central decision-making body for the project, overseeing both strategic and technical decisions of the open source project GPT-Engineer.

#### Composition:
- The Board consists of the project's founder, Anton Osika, and representatives from each significant contributing entity, including individual contributors and commercial partners.
- The board is restricted to a maximum of 7 seats.
- New board members are admitted by majority vote.
- Board members may be expelled by majority vote.

## II. Roles and Responsibilities

### Veto due to Ethical Considerations
- The founder has veto right over any decisions made by the Board.
- This veto power is a safeguard to ensure the project's direction remains true to its original vision and ethos.

### Contribution-Conditioned Decision Making
- Each board member has one vote as long as they qualify as active contributors.
- To qualify as an active contributor, a board member or the entity they represent, must have made 6 significant contributions on the GPT-Engineer GitHub page over the past 90 days.
- A significant contribution is:
  - A merged pull request with at least 3 lines of code.
  - Engagement in a GitHub/Discord bug report, where the board members' input leads to the confirmed resolution of the bug. If the solution is in terms of a merged pull request, the bug resolution together with the merged pull request counts as one significant contribution.
  - A non-code, but necessary, community activity agreed on by the board, such as administration, corporate design, workflow design etc, deemed to take more than 1 hour. Participation in meetings or discussions does not count as a significant contribution.
- A board member may retain its seat on the board without voting right.

## III. Decision-Making Process

### Majority Voting
- Decisions are made based on a simple majority vote. Majority means more than half of board members with voting rights agree on one decision, regardless of the number of choices.
- The founder's veto can override the majority decision if exercised.

### Regular Meetings and Reporting
- The Board will convene regularly, with the frequency of meetings decided by the Board members.
- Decisions, discussion points, and contributions will be transparently documented and shared within the project community.

## IV. Data Access and Confidentiality

### Board Members' Right to Access Data
- Any confidential data collected by GPT-Engineer is accessible to the board members after signing a relevant non-disclosure agreement (NDA).
- A relevant NDA requires a board member to erase any copies of confidential data obtained by the time of leaving the board.

## V. Scope of Voting

### Essential Topics
- Board voting is restricted to essential topics.
- Essential topics include essential technical topics and essential community topics.
- An essential technical topic is a change in the GPT-engineer code base that is likely to introduce breaking changes, or significantly change the user experience for users and developers.
- Essential community topics are changes to the community's governance or other central policy documents such as the readme or license.
- Day-to-day tasks such as bug fixes or implementation of new features outside the core module do not require voting.

## VI. Transparency

### Commitment to Transparency
- The governance process will be transparent, with key decisions, meeting minutes, and voting results publicly available, except for sensitive or confidential matters.

## VII. Amendments

### Changes to Governance Structure
- The governance model can be revised as the project evolves. Proposals for changes can be made by any Board member and will require a majority vote for adoption.

## VIII. The GPT-Engineer Brand

### Copyright and Stewardship
- The creator of GPT-engineer (Anton Osika) will be the steward of the GPT-engineer brand to decide when and how it can be used, and is committed to never jeopardizing the interest of the open source community in this stewardship.
- Anton Osika possesses the exclusive intellectual property rights for the trademark 'GPT-engineer,' encompassing all case variations such as 'gpt-engineer,' 'GPT-engineer,' and 'GPTE.' This ownership extends to the exclusive legal authority to utilize the 'GPT-engineer' trademark in the establishment and branding of both commercial and non-profit entities. It includes, but is not limited to, the use of the trademark in business names, logos, marketing materials, and other forms of corporate identity. Any use of the 'GPT-engineer' trademark, in any of its case variations, by other parties for commercial or non-commercial purposes requires express permission or a license agreement from Anton Osika.

# Current Board Members
- Anton Osika
- Axel Theorell
- Corey Gallon
- Peter Harrington
- Theo McCabe


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2023 Anton Osika

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: MANIFEST.in
================================================
recursive-include gpt_engineer/preprompts *


================================================
FILE: Makefile
================================================
#Sets the default shell for executing commands as /bin/bash and specifies command should be executed in a Bash shell.
SHELL := /bin/bash

# Color codes for terminal output
COLOR_RESET=\033[0m
COLOR_CYAN=\033[1;36m
COLOR_GREEN=\033[1;32m

# Defines the targets help, install, dev-install, and run as phony targets.
.PHONY: help install run

#sets the default goal to help when no target is specified on the command line.
.DEFAULT_GOAL := help

#Disables echoing of commands.
.SILENT:

#Sets the variable name to the second word from the MAKECMDGOALS.
name := $(word 2,$(MAKECMDGOALS))

#Defines a target named help.
help:
	@echo "Please use 'make <target>' where <target> is one of the following:"
	@echo "  help           	Return this message with usage instructions."
	@echo "  install        	Will install the dependencies using Poetry."
	@echo "  run <folder_name>  Runs GPT Engineer on the folder with the given name."

#Defines a target named install. This target will install the project using Poetry.
install: poetry-install install-pre-commit farewell

#Defines a target named poetry-install. This target will install the project dependencies using Poetry.
poetry-install:
	@echo -e "$(COLOR_CYAN)Installing project with Poetry...$(COLOR_RESET)" && \
	poetry install

#Defines a target named install-pre-commit. This target will install the pre-commit hooks.
install-pre-commit:
	@echo -e "$(COLOR_CYAN)Installing pre-commit hooks...$(COLOR_RESET)" && \
	poetry run pre-commit install

#Defines a target named farewell. This target will print a farewell message.
farewell:
	@echo -e "$(COLOR_GREEN)All done!$(COLOR_RESET)"

#Defines a target named run. This target will run GPT Engineer on the folder with the given name.
run:
	@echo -e "$(COLOR_CYAN)Running GPT Engineer on $(COLOR_GREEN)$(name)$(COLOR_CYAN) folder...$(COLOR_RESET)" && \
	poetry run gpt-engineer projects/$(name)

# Counts the lines of code in the project
cloc:
	cloc . --exclude-dir=node_modules,dist,build,.mypy_cache,benchmark --exclude-list-file=.gitignore --fullpath --not-match-d='docs/_build' --by-file


================================================
FILE: README.md
================================================
# gpt-engineer

[![GitHub Repo stars](https://img.shields.io/github/stars/gpt-engineer-org/gpt-engineer?style=social)](https://github.com/gpt-engineer-org/gpt-engineer)
[![Discord Follow](https://dcbadge.vercel.app/api/server/8tcDQ89Ej2?style=flat)](https://discord.gg/8tcDQ89Ej2)
[![License](https://img.shields.io/github/license/gpt-engineer-org/gpt-engineer)](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/LICENSE)
[![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/gpt-engineer-org/gpt-engineer)](https://github.com/gpt-engineer-org/gpt-engineer/issues)
![GitHub Release](https://img.shields.io/github/v/release/gpt-engineer-org/gpt-engineer)
[![Twitter Follow](https://img.shields.io/twitter/follow/antonosika?style=social)](https://twitter.com/antonosika)

The OG code genereation experimentation platform!

If you are looking for the evolution that is an opinionated, managed service – check out gptengineer.app.

If you are looking for a well maintained hackable CLI for – check out aider.


gpt-engineer lets you:
- Specify software in natural language
- Sit back and watch as an AI writes and executes the code
- Ask the AI to implement improvements

## Getting Started

### Install gpt-engineer

For **stable** release:

- `python -m pip install gpt-engineer`

For **development**:
- `git clone https://github.com/gpt-engineer-org/gpt-engineer.git`
- `cd gpt-engineer`
- `poetry install`
- `poetry shell` to activate the virtual environment

We actively support Python 3.10 - 3.12. The last version to support Python 3.8 - 3.9 was [0.2.6](https://pypi.org/project/gpt-engineer/0.2.6/).

### Setup API key

Choose **one** of:
- Export env variable (you can add this to .bashrc so that you don't have to do it each time you start the terminal)
    - `export OPENAI_API_KEY=[your api key]`
- .env file:
    - Create a copy of `.env.template` named `.env`
    - Add your OPENAI_API_KEY in .env
- Custom model:
    - See [docs](https://gpt-engineer.readthedocs.io/en/latest/open_models.html), supports local model, azure, etc.

Check the [Windows README](./WINDOWS_README.md) for Windows usage.

**Other ways to run:**
- Use Docker ([instructions](docker/README.md))
- Do everything in your browser:
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/gpt-engineer-org/gpt-engineer/codespaces)

### Create new code (default usage)
- Create an empty folder for your project anywhere on your computer
- Create a file called `prompt` (no extension) inside your new folder and fill it with instructions
- Run `gpte <project_dir>` with a relative path to your folder
  - For example: `gpte projects/my-new-project` from the gpt-engineer directory root with your new folder in `projects/`

### Improve existing code
- Locate a folder with code which you want to improve anywhere on your computer
- Create a file called `prompt` (no extension) inside your new folder and fill it with instructions for how you want to improve the code
- Run `gpte <project_dir> -i` with a relative path to your folder
  - For example: `gpte projects/my-old-project -i` from the gpt-engineer directory root with your folder in `projects/`

### Benchmark custom agents
- gpt-engineer installs the binary 'bench', which gives you a simple interface for benchmarking your own agent implementations against popular public datasets.
- The easiest way to get started with benchmarking is by checking out the [template](https://github.com/gpt-engineer-org/gpte-bench-template) repo, which contains detailed instructions and an agent template.
- Currently supported benchmark:
  - [APPS](https://github.com/hendrycks/apps)
  - [MBPP](https://github.com/google-research/google-research/tree/master/mbpp)

The community has started work with different benchmarking initiatives, as described in [this Loom](https://www.loom.com/share/206805143fbb4302b5455a5329eaab17?sid=f689608f-8e49-44f7-b55f-4c81e9dc93e6) video.

### Research
Some of our community members have worked on different research briefs that could be taken further. See [this document](https://docs.google.com/document/d/1qmOj2DvdPc6syIAm8iISZFpfik26BYw7ZziD5c-9G0E/edit?usp=sharing) if you are interested.

## Terms
By running gpt-engineer, you agree to our [terms](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/TERMS_OF_USE.md).


## Relation to gptengineer.app (GPT Engineer)
[gptengineer.app](https://gptengineer.app/) is a commercial project for the automatic generation of web apps.
It features a UI for non-technical users connected to a git-controlled codebase.
The gptengineer.app team is actively supporting the open source community.


## Features

### Pre Prompts
You can specify the "identity" of the AI agent by overriding the `preprompts` folder with your own version of the `preprompts`. You can do so via the `--use-custom-preprompts` argument.

Editing the `preprompts` is how you make the agent remember things between projects.

### Vision

By default, gpt-engineer expects text input via a `prompt` file. It can also accept image inputs for vision-capable models. This can be useful for adding UX or architecture diagrams as additional context for GPT Engineer. You can do this by specifying an image directory with the `—-image_directory` flag and setting a vision-capable model in the second CLI argument.

E.g. `gpte projects/example-vision gpt-4-vision-preview --prompt_file prompt/text --image_directory prompt/images -i`

### Open source, local and alternative models

By default, gpt-engineer supports OpenAI Models via the OpenAI API or Azure OpenAI API, as well as Anthropic models.

With a little extra setup, you can also run with open source models like WizardCoder. See the [documentation](https://gpt-engineer.readthedocs.io/en/latest/open_models.html) for example instructions.

## Mission

The gpt-engineer community mission is to **maintain tools that coding agent builders can use and facilitate collaboration in the open source community**.

If you are interested in contributing to this, we are interested in having you.

If you want to see our broader ambitions, check out the [roadmap](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/ROADMAP.md), and join
[discord](https://discord.gg/8tcDQ89Ej2)
to learn how you can [contribute](.github/CONTRIBUTING.md) to it.

gpt-engineer is [governed](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/GOVERNANCE.md) by a board of long-term contributors. If you contribute routinely and have an interest in shaping the future of gpt-engineer, you will be considered for the board.

## Significant contributors
<ul style="list-style-type: none; padding: 0; display: flex; flex-wrap: wrap;"> <li style="margin-right: 10px; margin-bottom: 10px;"> <a href="https://github.com/ATheorell"> <img src="https://avatars.githubusercontent.com/u/143704446?s=64&v=4" alt="@ATheorell" width="32" height="32" style="border-radius: 50%;"> @ATheorell </a> </li> <li style="margin-right: 10px; margin-bottom: 10px;"> <a href="https://github.com/similato87"> <img src="https://avatars.githubusercontent.com/u/71301573?s=64&v=4" alt="@similato87" width="32" height="32" style="border-radius: 50%;"> @similato87 </a> </li> <li style="margin-right: 10px; margin-bottom: 10px;"> <a href="https://github.com/TheoMcCabe"> <img src="https://avatars.githubusercontent.com/u/9841960?s=64&v=4" alt="@TheoMcCabe" width="32" height="32" style="border-radius: 50%;"> @TheoMcCabe </a> </li> <li style="margin-right: 10px; margin-bottom: 10px;"> <a href="https://github.com/captivus"> <img src="https://avatars.githubusercontent.com/u/366332?s=64&v=4" alt="@captivus" width="32" height="32" style="border-radius: 50%;"> @captivus </a> </li> </ul>


## Example



https://github.com/gpt-engineer-org/gpt-engineer/assets/4467025/40d0a9a8-82d0-4432-9376-136df0d57c99


================================================
FILE: ROADMAP.md
================================================
# Roadmap

<img width="800" alt="image" src="https://github.com/gpt-engineer-org/gpt-engineer/assets/48092564/06bce891-00ef-4052-bbbd-77af8b843fff">


This document is a general roadmap guide to the gpt-engineer project's strategic direction.
Our goal is to continually improve by focusing on three main pillars:
- User Experience,
- Technical Features, and
- Performance Tracking/Testing.

Each pillar is supported by a set of epics, reflecting our major goals and initiatives.


## Tracking Progress with GitHub Projects

We are using [GitHub Projects](https://github.com/orgs/gpt-engineer-org/projects/3) to track the progress of our roadmap.

Each issue within our project is categorized under one of the main pillars and, in most cases, associated epics. You can check our [Project's README](https://github.com/orgs/gpt-engineer-org/projects/3?pane=info) section to understand better our logic and organization.



# How you can help out

You can:

- Post a "design" as a Google Doc in our [Discord](https://discord.com/channels/1119885301872070706/1120698764445880350), and ask for feedback to address one of the items in the roadmap
- Submit PRs to address one of the items in the roadmap
- Do a review of someone else's PR and propose next steps (further review, merge, close)

🙌 Volunteer work in any of these will get acknowledged.🙌


================================================
FILE: TERMS_OF_USE.md
================================================
# Terms of Use

Welcome to gpt-engineer! By utilizing this powerful tool, you acknowledge and agree to the following comprehensive Terms of Use. We also encourage you to review the linked [disclaimer of warranty](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/DISCLAIMER.md) for additional information.

Both OpenAI, L.L.C. and the dedicated creators behind the remarkable gpt-engineer have implemented a data collection process focused on enhancing the product's capabilities. This endeavor is undertaken with utmost care and dedication to safeguarding user privacy. Rest assured that no information that could be directly attributed to any individual is stored.

It's important to be aware that the utilization of natural text inputs, including the 'prompt' and 'feedback' files, may be subject to storage. While it's theoretically possible to establish connections between a person's writing style or content within these files and their real-life identity, please note that the creators of gpt-engineer explicitly assure that such attempts will never be made.

For a deeper understanding of OpenAI's overarching terms of use, we encourage you to explore the details available [here](https://openai.com/policies/terms-of-use).

Optionally, gpt-engineer collects usage data for the purpose of improving gpt-engineer. Data collection only happens when a consent file called .gpte_consent is present in the gpt-engineer directory. Note that gpt-engineer cannot prevent that data streams passing through gpt-engineer to a third party may be stored by that third party (for example OpenAI).

Your engagement with gpt-engineer is an acknowledgment and acceptance of these terms, demonstrating your commitment to using this tool responsibly and within the bounds of ethical conduct. We appreciate your trust and look forward to the exciting possibilities that gpt-engineer can offer in your endeavors.


================================================
FILE: WINDOWS_README.md
================================================
# Windows Setup
## Short version

On Windows, follow the standard [README.md](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/README.md), but to set API key do one of:
- `set OPENAI_API_KEY=[your api key]` on cmd
- `$env:OPENAI_API_KEY="[your api key]"` on powershell

## Full setup guide

Choose either **stable** or **development**.

For **stable** release:

Run `pip install gpt-engineer` in the command line as an administrator

Or:

  1. Open your web browser and navigate to the Python Package Index (PyPI) website: <https://pypi.org/project/gpt-engineer/>.
  2. On the PyPI page for the gpt-engineer package, locate the "Download files" section. Here you'll find a list of available versions and their corresponding download links.
  3. Identify the version of gpt-engineer you want to install and click on the associated download link. This will download the package file (usually a .tar.gz or .whl file) to your computer.
  4. Once the package file is downloaded, open your Python development environment or IDE.
  5. In your Python development environment, look for an option to install packages or manage dependencies. The exact location and terminology may vary depending on your IDE. For example, in PyCharm, you can go to "File" > "Settings" > "Project: \<project-name>" > "Python Interpreter" to manage packages.
  6. In the package management interface, you should see a list of installed packages. Look for an option to add or install a new package.
  7. Click on the "Add Package" or "Install Package" button.
  8. In the package installation dialog, choose the option to install from a file or from a local source.
  9. Browse and select the downloaded gpt-engineer package file from your computer.

For **development**:

- `git clone git@github.com:gpt-engineer-org/gpt-engineer.git`
- `cd gpt-engineer`
- `poetry install`
- `poetry shell` to activate the virtual environment

### Setup

With an api key from OpenAI:

Run `set OPENAI_API_KEY=[your API key]` in the command line

Or:

  1. In the Start Menu, type to search for "Environment Variables" and click on "Edit the system environment variables".
  2. In the System Properties window, click on the "Environment Variables" button.
  3. In the Environment Variables window, you'll see two sections: User variables and System variables.
  4. To set a user-specific environment variable, select the "New" button under the User variables section.
  5. To set a system-wide environment variable, select the "New" button under the System variables section.
  6. Enter the variable name "OPENAI_API_KEY" in the "Variable name" field.
  7. Enter the variable value (e.g., your API key) in the "Variable value" field.
  8. Click "OK" to save the changes.
  9. Close any open command prompt or application windows and reopen them for the changes to take effect.

Now you can use `%OPENAI_API_KEY%` when prompted to input your key.

### Run

- Create an empty folder. If inside the repo, you can:
  - Run `xcopy /E projects\example projects\my-new-project` in the command line
  - Or hold CTRL and drag the folder down to create a copy, then rename to fit your project
- Fill in the `prompt` file in your new folder
- `gpt-engineer projects/my-new-project`
  - (Note, `gpt-engineer --help` lets you see all available options. For example `--steps use_feedback` lets you improve/fix code in a project)

By running gpt-engineer you agree to our [ToS](https://github.com/gpt-engineer-org/gpt-engineer/blob/main/TERMS_OF_USE.md).

### Results

- Check the generated files in `projects/my-new-project/workspace`


================================================
FILE: citation.cff
================================================
cff-version: 1.0.0
message: "If you use this software, please cite it as below."
authors:
  - family-names: Osika
    given-names: Anton
title: gpt-engineer
version: 0.1.0
date-released: 2023-04-23
repository-code: https://github.com/gpt-engineer-org/gpt-engineer
url: https://gpt-engineer.readthedocs.io


================================================
FILE: docker/Dockerfile
================================================
# Stage 1: Builder stage
FROM python:3.11-slim AS builder

RUN apt-get update && apt-get install -y --no-install-recommends \
  tk \
  tcl \
  curl \
  git \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY . .

RUN pip install --no-cache-dir -e .

# Stage 2: Final stage
FROM python:3.11-slim

WORKDIR /app

COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
COPY --from=builder /usr/bin /usr/bin
COPY --from=builder /app .

COPY docker/entrypoint.sh .

ENTRYPOINT ["bash", "/app/entrypoint.sh"]


================================================
FILE: docker/README.md
================================================
# Getting Started Using Docker

This guide provides step-by-step instructions on how to set up and run the Docker environment for your GPT-Engineer project.

## Prerequisites

- Docker installed on your machine.
- Git (for cloning the repository).

## Setup Instructions

### Using Docker CLI

1. **Clone the Repository**

    ```bash
    git clone https://github.com/gpt-engineer-org/gpt-engineer.git
    cd gpt-engineer
    ```

2. **Build the Docker Image**

    ```bash
    docker build --rm -t gpt-engineer -f docker/Dockerfile .
    ```

3. **Run the Docker Container**

    ```bash
    docker run -it --rm -e OPENAI_API_KEY="YOUR_OPENAI_KEY" -v ./your-project:/project gpt-engineer
    ```

    Replace `YOUR_OPENAI_KEY` with your actual OpenAI API key. The `-v` flag mounts your local `your-project` directory inside the container. Replace this with your actual project directory.  Ensure this directory contains all necessary files, including the `prompt` file.

### Using Docker Compose

1. **Clone the Repository** (if not already done)

    ```bash
    git clone https://github.com/gpt-engineer-org/gpt-engineer.git
    cd gpt-engineer
    ```

2. **Build and Run using Docker Compose**

    ```bash
    docker-compose -f docker-compose.yml build
    docker-compose run --rm gpt-engineer
    ```

    Set the `OPENAI_API_KEY` in the `docker/docker-compose.yml` using an `.env` file or as an environment variable. Mount your project directory to the container using volumes, e.g., `"./projects/example:/project"` where `./projects/example` is the path to your project directory.

3. **Another alternative using Docker Compose**

    Since there is only one `docker-compose.yml` file, you could run it without the -f option.
    - `docker compose up -d --build` - To build and start the containers defined in your `docker-compose.yml` file in detached mode
    - `docker compose up -d` - To start the containers defined in your `docker-compose.yml` file in detached mode
    - `docker compose down` - To stop and remove all containers, networks, and volumes associated with the `docker-compose.yml`
    - `docker compose restart` - To restart the containers defined in the `docker-compose.yml` file

## Debugging

To facilitate debugging, you can run a shell inside the built Docker image:

```bash
docker run -it --entrypoint /bin/bash gpt-engineer
```

This opens a shell inside the Docker container, allowing you to execute commands and inspect the environment manually.


================================================
FILE: docker/entrypoint.sh
================================================
#!/usr/bin/env bash
# -*- coding: utf-8 -*-

project_dir="/project"

# Run the gpt engineer script
gpt-engineer $project_dir "$@"

# Patch the permissions of the generated files to be owned by nobody except prompt file
find "$project_dir" -mindepth 1 -maxdepth 1 ! -path "$project_dir/prompt" -exec chown -R nobody:nogroup {} + -exec chmod -R 777 {} +


================================================
FILE: docker-compose.yml
================================================
services:
  gpt-engineer:
    build:
      context: .
      dockerfile: docker/Dockerfile
    stdin_open: true
    tty: true
    # Set the API key from the .env file
    env_file:
      - .env
    ##  OR set the API key directly
    # environment:
      # - OPENAI_API_KEY=YOUR_API_KEY
    image: gpt-engineer
    volumes:
      - ./projects/example:/project


================================================
FILE: docs/Makefile
================================================
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXBUILD   = python -msphinx
SPHINXPROJ    = gpt_engineer
SOURCEDIR     = .
BUILDDIR      = _build

# Put it first so that "make" without argument is like "make help".
help:
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)


================================================
FILE: docs/api_reference.rst
================================================
.. _api_reference:

=============
API Reference
=============

:mod:`gpt_engineer.applications`: Applications
===============================================

.. automodule:: gpt_engineer.applications
    :no-members:
    :no-inherited-members:

Classes
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: applications
    :template: class.rst

    applications.cli.cli_agent.CliAgent
    applications.cli.file_selector.DisplayablePath

Functions
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: applications

    applications.cli.collect.collect_and_send_human_review
    applications.cli.collect.collect_learnings
    applications.cli.collect.send_learning
    applications.cli.learning.ask_collection_consent
    applications.cli.learning.ask_for_valid_input
    applications.cli.learning.check_collection_consent
    applications.cli.learning.extract_learning
    applications.cli.learning.get_session
    applications.cli.learning.human_review_input
    applications.cli.main.get_preprompts_path
    applications.cli.main.load_env_if_needed
    applications.cli.main.load_prompt
    applications.cli.main.main

:mod:`gpt_engineer.benchmark`: Benchmark
=========================================

.. automodule:: gpt_engineer.benchmark
    :no-members:
    :no-inherited-members:

Functions
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: benchmark

    benchmark.__main__.get_agent
    benchmark.__main__.main
    benchmark.benchmarks.gpteng.eval_tools.assert_exists_in_source_code
    benchmark.benchmarks.gpteng.eval_tools.check_evaluation_component
    benchmark.benchmarks.gpteng.eval_tools.check_language
    benchmark.benchmarks.gpteng.eval_tools.run_code_class_has_property
    benchmark.benchmarks.gpteng.eval_tools.run_code_class_has_property_w_value
    benchmark.benchmarks.gpteng.eval_tools.run_code_eval_function
    benchmark.benchmarks.gpteng.load.eval_to_task
    benchmark.benchmarks.gpteng.load.expect_to_assertion
    benchmark.benchmarks.gpteng.load.load_gpteng
    benchmark.benchmarks.gptme.load.load_gptme
    benchmark.benchmarks.load.get_benchmark
    benchmark.run.print_results
    benchmark.run.run

:mod:`gpt_engineer.core`: Core
===============================

.. automodule:: gpt_engineer.core
    :no-members:
    :no-inherited-members:

Classes
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: core
    :template: class.rst

    core.base_agent.BaseAgent
    core.base_execution_env.BaseExecutionEnv
    core.default.disk_execution_env.DiskExecutionEnv
    core.default.disk_memory.DiskMemory
    core.default.simple_agent.SimpleAgent
    core.files_dict.FilesDict
    core.version_manager.BaseVersionManager

Functions
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: core

    core.ai.serialize_messages
    core.chat_to_files.apply_diffs
    core.chat_to_files.chat_to_files_dict
    core.chat_to_files.parse_diff_block
    core.chat_to_files.parse_diffs
    core.chat_to_files.parse_hunk_header
    core.default.paths.memory_path
    core.default.paths.metadata_path
    core.default.simple_agent.default_config_agent
    core.default.steps.curr_fn
    core.default.steps.execute_entrypoint
    core.default.steps.gen_code
    core.default.steps.gen_entrypoint
    core.default.steps.improve
    core.default.steps.salvage_correct_hunks
    core.default.steps.setup_sys_prompt
    core.default.steps.setup_sys_prompt_existing_code
    core.diff.count_ratio
    core.diff.is_similar
    core.files_dict.file_to_lines_dict

:mod:`gpt_engineer.tools`: Tools
=================================

.. automodule:: gpt_engineer.tools
    :no-members:
    :no-inherited-members:

Functions
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: tools

    tools.custom_steps.clarified_gen
    tools.custom_steps.get_platform_info
    tools.custom_steps.lite_gen
    tools.custom_steps.self_heal


================================================
FILE: docs/code_conduct_link.rst
================================================
.. include:: ../.github/CODE_OF_CONDUCT.md
   :parser: myst_parser.sphinx_


================================================
FILE: docs/conf.py
================================================
#!/usr/bin/env python
#
# file_processor documentation build configuration file, created by
# sphinx-quickstart on Fri Jun  9 13:47:02 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

# If extensions (or modules to document with autodoc) are in another
# directory, add these directories to sys.path here. If the directory is
# relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#
import os
import sys

from pathlib import Path

import toml

sys.path.insert(0, os.path.abspath(".."))

ROOT_DIR = Path(__file__).parents[1].absolute()

with open("../pyproject.toml") as f:
    data = toml.load(f)


# The master toctree document.
master_doc = "index"

# General information about the project.
project = data["tool"]["poetry"]["name"]
copyright = "2023 Anton Osika"
author = " Anton Osika & Contributors"

# The version info for the project you're documenting, acts as replacement
# for |version| and |release|, also used in various other places throughout
# the built documents.
#
# The short X.Y version.
version = data["tool"]["poetry"]["version"]
# The full version, including alpha/beta/rc tags.
release = data["tool"]["poetry"]["version"]


# -- General configuration ---------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
    "sphinx.ext.autodoc",
    "sphinx.ext.autodoc.typehints",
    "sphinx.ext.autosummary",
    "sphinx.ext.napoleon",
    "sphinx.ext.viewcode",
    "sphinx_copybutton",
    "myst_parser",
    "IPython.sphinxext.ipython_console_highlighting",
]

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:

source_suffix = [".rst", ".md"]

autodoc_pydantic_model_show_json = False
autodoc_pydantic_field_list_validators = False
autodoc_pydantic_config_members = False
autodoc_pydantic_model_show_config_summary = False
autodoc_pydantic_model_show_validator_members = False
autodoc_pydantic_model_show_validator_summary = False
autodoc_pydantic_model_signature_prefix = "class"
autodoc_pydantic_field_signature_prefix = "param"
autodoc_member_order = "groupwise"
autoclass_content = "both"
autodoc_typehints_format = "short"

autodoc_default_options = {
    "members": True,
    "show-inheritance": True,
    "inherited-members": "BaseModel",
    "undoc-members": False,
}

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]


# source_suffix = '.rst'


# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en"

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False


# -- Options for HTML output -------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
# html_theme = 'alabaster'
html_theme = "sphinx_rtd_theme"

# Theme options are theme-specific and customize the look and feel of a
# theme further.  For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ["_static"]


# -- Options for HTMLHelp output ---------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = "gpt_engineerdoc"


# -- Options for LaTeX output ------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',
    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',
    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',
    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto, manual, or own class]).
latex_documents = [
    (master_doc, "gpt_engineer.tex", "GPT-ENgineer Documentation", "manual"),
]


# -- Options for manual page output ------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "gpt_engineer", "GPT-Engineer Documentation", [author], 1)]


# -- Options for Texinfo output ----------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (
        master_doc,
        "gpt_engineer",
        "GPT-Engineer Documentation",
        author,
        "gpt_engineer",
        "One line description of project.",
        "Miscellaneous",
    ),
]

# generate autosummary even if no references
autosummary_generate = True

myst_enable_extensions = [
    "colon_fence",
]

myst_all_links_external = True


================================================
FILE: docs/contributing_link.rst
================================================
.. include:: ../.github/CONTRIBUTING.md
   :parser: myst_parser.sphinx_


================================================
FILE: docs/create_api_rst.py
================================================
"""Script for auto-generating api_reference.rst"""
import glob
import re

from pathlib import Path

ROOT_DIR = Path(__file__).parents[1].absolute()
print(ROOT_DIR)
PKG_DIR = ROOT_DIR / "gpt_engineer"
WRITE_FILE = Path(__file__).parent / "api_reference.rst"


def load_members() -> dict:
    members: dict = {}
    for py in glob.glob(str(PKG_DIR) + "/**/*.py", recursive=True):
        module = py[len(str(PKG_DIR)) + 1 :].replace(".py", "").replace("/", ".")
        top_level = module.split(".")[0]
        if top_level not in members:
            members[top_level] = {"classes": [], "functions": []}
        with open(py, "r") as f:
            for line in f.readlines():
                cls = re.findall(r"^class ([^_].*)\(", line)
                members[top_level]["classes"].extend([module + "." + c for c in cls])
                func = re.findall(r"^def ([^_].*)\(", line)
                afunc = re.findall(r"^async def ([^_].*)\(", line)
                func_strings = [module + "." + f for f in func + afunc]
                members[top_level]["functions"].extend(func_strings)
    return members


def construct_doc(members: dict) -> str:
    full_doc = """\
.. _api_reference:

=============
API Reference
=============

"""
    for module, _members in sorted(members.items(), key=lambda kv: kv[0]):
        classes = _members["classes"]
        functions = _members["functions"]
        if not (classes or functions):
            continue

        module_title = module.replace("_", " ").title()
        if module_title == "Llms":
            module_title = "LLMs"
        section = f":mod:`gpt_engineer.{module}`: {module_title}"
        full_doc += f"""\
{section}
{'=' * (len(section) + 1)}

.. automodule:: gpt_engineer.{module}
    :no-members:
    :no-inherited-members:

"""

        if classes:
            cstring = "\n    ".join(sorted(classes))
            full_doc += f"""\
Classes
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: {module}
    :template: class.rst

    {cstring}

"""
        if functions:
            fstring = "\n    ".join(sorted(functions))
            full_doc += f"""\
Functions
--------------
.. currentmodule:: gpt_engineer

.. autosummary::
    :toctree: {module}

    {fstring}

"""
    return full_doc


def main() -> None:
    members = load_members()
    full_doc = construct_doc(members)
    with open(WRITE_FILE, "w") as f:
        f.write(full_doc)


if __name__ == "__main__":
    main()


================================================
FILE: docs/disclaimer_link.rst
================================================
.. include:: ../DISCLAIMER.md
   :parser: myst_parser.sphinx_


================================================
FILE: docs/docs_building.md
================================================
Building Docs with Sphinx
=========================

This example shows a basic Sphinx docs project with Read the Docs. This project is using `sphinx` with `readthedocs`
project template.

Some useful links are given below to lear and contribute in the project.

📚 [docs/](https://www.sphinx-doc.org/en/master/usage/quickstart.html)<br>
A basic Sphinx project lives in `docs/`, it was generated using Sphinx defaults. All the `*.rst` & `*.md` make up sections in the documentation. Both `.rst` and `.md` formats are supported in this project

⚙️ [.readthedocs.yaml](https://docs.readthedocs.io/en/stable/config-file/v2.html)<br>
Read the Docs Build configuration is stored in `.readthedocs.yaml`.


Example Project usage
---------------------

``Poetry`` is the package manager for ``gpt-engineer``. In order to build documentation, we have to add docs requirements in
development environment.

This project has a standard readthedocs layout which is built by Read the Docs almost the same way that you would build it
locally (on your own laptop!).

You can build and view this documentation project locally - we recommend that you activate a ``poetry shell``.

Update ``repository_stats.md`` file under ``docs/intro``

```console
# Install required Python dependencies (MkDocs etc.)
poetry install
cd docs/

# Create the `api_reference.rst`
python create_api_rst.py

# Build the docs
make html

## Alternatively, to rebuild the docs on changes with live-reload in the browser
sphinx-autobuild . _build/html
```

Project Docs Structure
----------------------
If you are new to Read the Docs, you may want to refer to the [Read the Docs User documentation](https://docs.readthedocs.io/).

Below is the rundown of documentation structure for `pandasai`, you need to know:

1. place your `docs/` folder alongside your Python project.
2. copy `.readthedocs.yaml` and the `docs/` folder into your project root.
3. `docs/api_reference.rst` contains the API documentation created using `docstring`.  Run the `create_api_rst.py` to update the API reference file.
4. Project is using standard Google Docstring Style.
5. Rebuild the documentation locally to see that it works.
6. Documentation are hosted on [Read the Docs tutorial](https://docs.readthedocs.io/en/stable/tutorial/)


Read the Docs tutorial
----------------------

To get started with Read the Docs, you may also refer to the
[Read the Docs tutorial](https://docs.readthedocs.io/en/stable/tutorial/). I

With every release, build the documentation manually.


================================================
FILE: docs/examples/open_llms/README.md
================================================
# Test that the Open LLM is running

First start the server by using only CPU:

```bash
export model_path="TheBloke/CodeLlama-13B-GGUF/codellama-13b.Q8_0.gguf"
python -m llama_cpp.server --model $model_path
```

Or with GPU support (recommended):

```bash
python -m llama_cpp.server --model TheBloke/CodeLlama-13B-GGUF/codellama-13b.Q8_0.gguf --n_gpu_layers 1
```

If you have more `GPU` layers available set `--n_gpu_layers` to the higher number.

To find the amount of available  run the above command and look for `llm_load_tensors: offloaded 1/41 layers to GPU` in the output.

## Test API call

Set the environment variables:

```bash
export OPENAI_API_BASE="http://localhost:8000/v1"
export OPENAI_API_KEY="sk-xxx"
export MODEL_NAME="CodeLlama"
````

Then ping the model via `python` using `OpenAI` API:

```bash
python examples/open_llms/openai_api_interface.py
```

If you're not using `CodeLLama` make sure to change the `MODEL_NAME` parameter.

Or using `curl`:

```bash
curl --request POST \
     --url http://localhost:8000/v1/chat/completions \
     --header "Content-Type: application/json" \
     --data '{ "model": "CodeLlama", "prompt": "Who are you?", "max_tokens": 60}'
```

If this works also make sure that `langchain` interface works since that's how `gpte` interacts with LLMs.

## Langchain test

```bash
export MODEL_NAME="CodeLlama"
python examples/open_llms/langchain_interface.py
```

That's it 🤓 time to go back [to](/docs/open_models.md#running-the-example) and give `gpte` a try.


================================================
FILE: docs/examples/open_llms/langchain_interface.py
================================================
import os

from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model=os.getenv("MODEL_NAME"),
    temperature=0.1,
    callbacks=[StreamingStdOutCallbackHandler()],
    streaming=True,
)

prompt = (
    "Provide me with only the code for a simple python function that sums two numbers."
)

model.invoke(prompt)


================================================
FILE: docs/examples/open_llms/openai_api_interface.py
================================================
import os

from openai import OpenAI

client = OpenAI(
    base_url=os.getenv("OPENAI_API_BASE"), api_key=os.getenv("OPENAI_API_KEY")
)

response = client.chat.completions.create(
    model=os.getenv("MODEL_NAME"),
    messages=[
        {
            "role": "user",
            "content": "Provide me with only the code for a simple python function that sums two numbers.",
        },
    ],
    temperature=0.7,
    max_tokens=200,
)

print(response.choices[0].message.content)


================================================
FILE: docs/index.rst
================================================
Welcome to GPT-ENGINEER's Documentation
=======================================

.. toctree::
   :maxdepth: 2
   :caption: GET STARTED:

   introduction.md
   installation
   quickstart

.. toctree::
   :maxdepth: 2
   :caption: USER GUIDES:

   windows_readme_link
   open_models.md
   tracing_debugging.md

.. toctree::
   :maxdepth: 2
   :caption: CONTRIBUTE:

   contributing_link
   roadmap_link
   code_conduct_link
   disclaimer_link
   docs_building.md
   terms_link

.. toctree::
   :maxdepth: 2
   :caption: PACKAGE API:

   api_reference

Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`


================================================
FILE: docs/installation.rst
================================================
.. highlight:: shell

============
Installation
============


Stable release
--------------

To install ``gpt-engineer``, run this command in your terminal:

.. code-block:: console

    $ python -m pip install gpt-engineer

This is the preferred method to install ``gpt-engineer``, as it will always install the most recent stable release.

If you don't have `pip`_ installed, this `Python installation guide`_ can guide
you through the process.

.. note::

    When reporting bugs, please specify your installation method (using `pip install` or by building the repository) in the "Installation Method" section of the bug report template.

.. _pip: https://pip.pypa.io
.. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/


From sources
------------

The sources for ``gpt-engineer`` can be downloaded from the `Github repo`_.

You can either clone the public repository:

.. code-block:: console

    $ git clone https://github.com/gpt-engineer-org/gpt-engineer.git

Once you have a copy of the source, you can install it with:

.. code-block:: console

    $ cd gpt-engineer
    $ poetry install
    $ poetry shell


.. _Github repo: https://github.com/gpt-engineer-org/gpt-engineer.git

Troubleshooting
---------------

For mac and linux system, there are sometimes slim python installations that do not include the ``gpt-engineer`` requirement tkinter, which is a standard library and thus not pip installable.

To install tkinter on mac, you can for example use brew:

.. code-block:: console

    $ brew install python-tk

On debian-based linux systems you can use:

.. code-block:: console

    $ sudo apt-get install python3-tk


================================================
FILE: docs/introduction.md
================================================
# Introduction
``gpt-engineer`` is a project that uses LLMs (such as GPT-4) to automate the process of software engineering. It includes several Python scripts that interact with the LLM to generate code, clarify requirements, generate specifications, and more.

<br>

## Get started
[Here’s](/en/latest/installation.html) how to install ``gpt-engineer``, set up your environment, and start building.

We recommend following our [Quickstart](/en/latest/quickstart.html) guide to familiarize yourself with the framework by building your first application with ``gpt-engineer``.

<br>

## Example
You can find an example of the project in action here.

<video width="100%" controls>
  <source src="https://github.com/gpt-engineer-org/gpt-engineer/assets/4467025/6e362e45-4a94-4b0d-973d-393a31d92d9b
" type="video/mp4">
  Your browser does not support the video tag.
</video>


================================================
FILE: docs/make.bat
================================================
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
	set SPHINXBUILD=python -msphinx
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=file_processor

if "%1" == "" goto help

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
	echo.
	echo.The Sphinx module was not found. Make sure you have Sphinx installed,
	echo.then set the SPHINXBUILD environment variable to point to the full
	echo.path of the 'sphinx-build' executable. Alternatively you may add the
	echo.Sphinx directory to PATH.
	echo.
	echo.If you don't have Sphinx installed, grab it from
	echo.http://sphinx-doc.org/
	exit /b 1
)

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%

:end
popd


================================================
FILE: docs/open_models.md
================================================
Using with open/local models
============================

**Use `gpte` first with OpenAI models to get a feel for the `gpte` tool.**

**Then go play with experimental Open LLMs 🐉 support and try not to get 🔥!!**

At the moment the best option for coding is still the use of `gpt-4` models provided by OpenAI. But open models are catching up and are a good free and privacy-oriented alternative if you possess the proper hardware.

You can integrate `gpt-engineer` with open-source models by leveraging an OpenAI-compatible API.

We provide the minimal and cleanest solution below. What is described is not the only way to use open/local models, but the one we tested and would recommend to most users.

More details on why the solution below is recommended in [this blog post](https://zigabrencic.com/blog/2024-02-21).

Setup
-----

For inference engine we recommend for the users to use [llama.cpp](https://github.com/ggerganov/llama.cpp) with its `python` bindings `llama-cpp-python`.

We choose `llama.cpp` because:

- 1.) It supports the largest amount of hardware acceleration backends.
- 2.) It supports the diverse set of open LLMs.
- 3.) Is written in `python` and directly on top of `llama.cpp` inference engine.
- 4.) Supports the `openAI` API and `langchain` interface.

To install `llama-cpp-python` follow the official [installation docs](https://llama-cpp-python.readthedocs.io/en/latest/) and [those docs](https://llama-cpp-python.readthedocs.io/en/latest/install/macos/) for MacOS with Metal support.

If you want to benefit from proper hardware acceleration on your machine make sure to set up the proper compiler flags before installing your package.

- `linux`: `CMAKE_ARGS="-DLLAMA_BLAS=ON -DLLAMA_BLAS_VENDOR=OpenBLAS"`
- `macos` with Metal support: `CMAKE_ARGS="-DLLAMA_METAL=on"`
- `windows`: `$env:CMAKE_ARGS = "-DLLAMA_BLAS=ON -DLLAMA_BLAS_VENDOR=OpenBLAS"`

This will enable the `pip` installer to compile the `llama.cpp` with the proper hardware acceleration backend.

Then run:

```bash
pip install llama-cpp-python
```

For our use case we also need to set up the web server that `llama-cpp-python` library provides. To install:

```bash
pip install 'llama-cpp-python[server]'
```

For detailed use consult the [`llama-cpp-python` docs](https://llama-cpp-python.readthedocs.io/en/latest/server/).

Before we proceed we need to obtain the model weights in the `gguf` format. That should be a single file on your disk.

In case you have weights in other formats check the `llama-cpp-python` docs for conversion to `gguf` format.

Models in other formats `ggml`, `.safetensors`, etc. won't work without prior conversion to `gguf` file format with the solution described below!

Which open model to use?
==================

Your best choice would be:

- CodeLlama 70B
- Mixtral 8x7B

We are still testing this part, but the larger the model you can run the better. Sure the responses might be slower in terms of (token/s), but code quality will be higher.

For testing that the open LLM `gpte` setup works we recommend starting with a smaller model. You can download weights of [CodeLlama-13B-GGUF by the `TheBloke`](https://huggingface.co/TheBloke/CodeLlama-13B-GGUF) choose the largest model version you can run (for example `Q6_K`), since quantisation will degrade LLM performance.

Feel free to try out larger models on your hardware and see what happens.

Running the Example
==================

To see that your setup works check [test open LLM setup](examples/test_open_llm/README.md).

If above tests work proceed 😉

For checking that `gpte` works with the `CodeLLama` we recommend for you to create a project with `prompt` file content:

```
Write a python script that sums up two numbers. Provide only the `sum_two_numbers` function and nothing else.

Provide two tests:

assert(sum_two_numbers(100, 10) == 110)
assert(sum_two_numbers(10.1, 10) == 20.1)
```

Now run the LLM in separate terminal:

```bash
python -m llama_cpp.server --model $model_path --n_batch 256 --n_gpu_layers 30
```

Then in another terminal window set the following environment variables:

```bash
export OPENAI_API_BASE="http://localhost:8000/v1"
export OPENAI_API_KEY="sk-xxx"
export MODEL_NAME="CodeLLama"
export LOCAL_MODEL=true
```

And run `gpt-engineer` with the following command:

```bash
gpte <project_dir> $MODEL_NAME --lite --temperature 0.1
```

The `--lite` mode is needed for now since open models for some reason behave worse with too many instructions at the moment. Temperature is set to `0.1` to get consistent best possible results.

That's it.

*If sth. doesn't work as expected, or you figure out how to improve the open LLM support please let us know.*

Using Open Router models
==================

In case you don't posses the hardware to run local LLM's yourself you can use the hosting on [Open Router](https://openrouter.ai) and pay as you go for the tokens.

To set it up you need to Sign In and load purchase 💰 the LLM credits. Pricing per token is different for (each model](https://openrouter.ai/models), but mostly cheaper then Open AI.

Then create the API key.

To for example use [Meta: Llama 3 8B Instruct (extended)](https://openrouter.ai/models/meta-llama/llama-3-8b-instruct:extended) with `gpte` we need to set:

```bash
export OPENAI_API_BASE="https://openrouter.ai/api/v1"
export OPENAI_API_KEY="sk-key-from-open-router"
export MODEL_NAME="meta-llama/llama-3-8b-instruct:extended"
export LOCAL_MODEL=true
```

```bash
gpte <project_dir> $MODEL_NAME --lite --temperature 0.1
```

Using Azure models
==================

You set your Azure OpenAI key:
- `export OPENAI_API_KEY=[your api key]`

Then you call `gpt-engineer` with your service endpoint `--azure https://aoi-resource-name.openai.azure.com` and set your deployment name (which you created in the Azure AI Studio) as the model name (last `gpt-engineer` argument).

Example:
`gpt-engineer --azure https://myairesource.openai.azure.com ./projects/example/ my-gpt4-project-name`


================================================
FILE: docs/quickstart.rst
================================================
==========
Quickstart
==========

Installation
============

To install LangChain run:

.. code-block:: console

    $ python -m pip install gpt-engineer

For more details, see our [Installation guide](/instllation.html).

Setup API Key
=============

Choose one of the following:

- Export env variable (you can add this to ``.bashrc`` so that you don't have to do it each time you start the terminal)

  .. code-block:: console

      $ export OPENAI_API_KEY=[your api key]

- Add it to the ``.env`` file:

  - Create a copy of ``.env.template`` named ``.env``
  - Add your ``OPENAI_API_KEY`` in .env

- If you want to use a custom model, visit our docs on `using open models and azure models <./open_models.html>`_.

- To set API key on windows check the `Windows README <./windows_readme_link.html>`_.

Building with ``gpt-engineer``
==============================

Create new code (default usage)
-------------------------------

- Create an empty folder for your project anywhere on your computer
- Create a file called ``prompt`` (no extension) inside your new folder and fill it with instructions
- Run ``gpte <project_dir>`` with a relative path to your folder
- For example, if you create a new project inside the gpt-engineer ``/projects`` directory:

  .. code-block:: console

    $ gpte projects/my-new-project

Improve Existing Code
---------------------

- Locate a folder with code which you want to improve anywhere on your computer
- Create a file called ``prompt`` (no extension) inside your new folder and fill it with instructions for how you want to improve the code
- Run ``gpte <project_dir> -i`` with a relative path to your folder
- For example, if you want to run it against an existing project inside the gpt-engineer ``/projects`` directory:

  .. code-block:: console

    $ gpte projects/my-old-project -i

By running ``gpt-engineer`` you agree to our `terms <./terms_link.html>`_.

To **run in the browser** you can simply:

.. image:: https://github.com/codespaces/badge.svg
   :target: https://github.com/gpt-engineer-org/gpt-engineer/codespaces


================================================
FILE: docs/roadmap_link.rst
================================================
.. include:: ../ROADMAP.md
   :parser: myst_parser.sphinx_


================================================
FILE: docs/terms_link.rst
================================================
.. include:: ../TERMS_OF_USE.md
   :parser: myst_parser.sphinx_


================================================
FILE: docs/tracing_debugging.md
================================================
Tracing and Debugging with Weights and Biases
============================

## How to store results in Weights & Biases

W&B Prompts is a suite of LLMOps tools built for the development of LLM-powered applications. Use W&B Prompts to visualize and inspect the execution flow of your LLMs, analyze the inputs and outputs of your LLMs, view the intermediate results and securely store and manage your prompts and LLM chain configurations. Read more at https://docs.wandb.ai/guides/prompts

```shell
 $ export WANDB_API_KEY="YOUR-KEY"
 $ export LANGCHAIN_WANDB_TRACING=true
 ```

Sign up for free at https://wandb.ai


Debug and trace the execution of the AI generated code to compare across different experiments with `gpt-engineer` and related prompts
![](https://drive.google.com/uc?id=10wuLwyPbH00CoESsS2Q2q6mkdrtS91jd)


Automatically capture and save terminal `stdout` to one easily accessible and shareable webpage
![](https://drive.google.com/uc?id=1gVva7ZfpwbTSBsnNvId6iq09Gw5ETOks)


================================================
FILE: docs/windows_readme_link.rst
================================================
.. include:: ../WINDOWS_README.md
   :parser: myst_parser.sphinx_


================================================
FILE: gpt_engineer/__init__.py
================================================
# Adding convenience imports to the package

# from gpt_engineer.tools import code_vector_repository
# from gpt_engineer.core.default import on_disk_repository


================================================
FILE: gpt_engineer/applications/__init__.py
================================================


================================================
FILE: gpt_engineer/applications/cli/__init__.py
================================================


================================================
FILE: gpt_engineer/applications/cli/cli_agent.py
================================================
"""
This module provides the CliAgent class which manages the lifecycle of code generation and improvement
using an AI model. It includes functionalities to initialize code generation, improve existing code,
and process the code through various steps defined in the step bundle.
"""

from typing import Callable, Optional, TypeVar

# from gpt_engineer.core.default.git_version_manager import GitVersionManager
from gpt_engineer.core.ai import AI
from gpt_engineer.core.base_agent import BaseAgent
from gpt_engineer.core.base_execution_env import BaseExecutionEnv
from gpt_engineer.core.base_memory import BaseMemory
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.default.paths import PREPROMPTS_PATH
from gpt_engineer.core.default.steps import (
    execute_entrypoint,
    gen_code,
    gen_entrypoint,
    improve_fn,
)
from gpt_engineer.core.files_dict import FilesDict
from gpt_engineer.core.preprompts_holder import PrepromptsHolder
from gpt_engineer.core.prompt import Prompt

CodeGenType = TypeVar("CodeGenType", bound=Callable[[AI, str, BaseMemory], FilesDict])
CodeProcessor = TypeVar(
    "CodeProcessor", bound=Callable[[AI, BaseExecutionEnv, FilesDict], FilesDict]
)
ImproveType = TypeVar(
    "ImproveType", bound=Callable[[AI, str, FilesDict, BaseMemory], FilesDict]
)


class CliAgent(BaseAgent):
    """
    The `CliAgent` class is responsible for managing the lifecycle of code generation and improvement
    using an AI model. It orchestrates the generation of new code and the improvement of existing code
    based on given prompts and utilizes a memory system and execution environment for processing.

    Parameters
    ----------
    memory : BaseMemory
        An instance of a class that adheres to the BaseMemory interface, used for storing and retrieving
        information during the code generation process.
    execution_env : BaseExecutionEnv
        An instance of a class that adheres to the BaseExecutionEnv interface, used for executing code
        and managing the execution environment.
    ai : AI, optional
        An instance of the AI class that manages calls to the language model. If not provided, a default
        instance is created.
    code_gen_fn : CodeGenType, optional
        A callable that takes an AI instance, a prompt, and a memory instance to generate code. Defaults
        to the `gen_code` function.
    improve_fn : ImproveType, optional
        A callable that takes an AI instance, a prompt, a FilesDict instance, and a memory instance to
        improve code. Defaults to the `improve` function.
    process_code_fn : CodeProcessor, optional
        A callable that takes an AI instance, an execution environment, and a FilesDict instance to
        process code. Defaults to the `execute_entrypoint` function.
    preprompts_holder : PrepromptsHolder, optional
        An instance of PrepromptsHolder that manages preprompt templates. If not provided, a default
        instance is created using the PREPROMPTS_PATH.

    Attributes
    ----------
    memory : BaseMemory
        The memory instance where the agent stores and retrieves information.
    execution_env : BaseExecutionEnv
        The execution environment instance where the agent executes and manages code.
    ai : AI
        The AI instance used for interacting with the language model.
    code_gen_fn : CodeGenType
        The function used for generating code.
    improve_fn : ImproveType
        The function used for improving code.
    process_code_fn : CodeProcessor
        The function used for processing code.
    preprompts_holder : PrepromptsHolder
        The holder for preprompt templates.
    """

    def __init__(
        self,
        memory: BaseMemory,
        execution_env: BaseExecutionEnv,
        ai: AI = None,
        code_gen_fn: CodeGenType = gen_code,
        improve_fn: ImproveType = improve_fn,
        process_code_fn: CodeProcessor = execute_entrypoint,
        preprompts_holder: PrepromptsHolder = None,
    ):
        self.memory = memory
        self.execution_env = execution_env
        self.ai = ai or AI()
        self.code_gen_fn = code_gen_fn
        self.process_code_fn = process_code_fn
        self.improve_fn = improve_fn
        self.preprompts_holder = preprompts_holder or PrepromptsHolder(PREPROMPTS_PATH)

    @classmethod
    def with_default_config(
        cls,
        memory: DiskMemory,
        execution_env: DiskExecutionEnv,
        ai: AI = None,
        code_gen_fn: CodeGenType = gen_code,
        improve_fn: ImproveType = improve_fn,
        process_code_fn: CodeProcessor = execute_entrypoint,
        preprompts_holder: PrepromptsHolder = None,
        diff_timeout=3,
    ):
        """
        Creates a new instance of CliAgent with default configurations for memory, execution environment,
        AI, and other functional parameters.

        Parameters
        ----------
        memory : DiskMemory
            An instance of DiskMemory for storing and retrieving information.
        execution_env : DiskExecutionEnv
            An instance of DiskExecutionEnv for executing code.
        ai : AI, optional
            An instance of AI for interacting with the language model. Defaults to None, which will create
            a new AI instance.
        code_gen_fn : CodeGenType, optional
            A function for generating code. Defaults to `gen_code`.
        improve_fn : ImproveType, optional
            A function for improving code. Defaults to `improve`.
        process_code_fn : CodeProcessor, optional
            A function for processing code. Defaults to `execute_entrypoint`.
        preprompts_holder : PrepromptsHolder, optional
            An instance of PrepromptsHolder for managing preprompt templates. Defaults to None, which will
            create a new PrepromptsHolder instance using PREPROMPTS_PATH.

        Returns
        -------
        CliAgent
            An instance of CliAgent configured with the provided or default parameters.
        """
        return cls(
            memory=memory,
            execution_env=execution_env,
            ai=ai,
            code_gen_fn=code_gen_fn,
            process_code_fn=process_code_fn,
            improve_fn=improve_fn,
            preprompts_holder=preprompts_holder or PrepromptsHolder(PREPROMPTS_PATH),
        )

    def init(self, prompt: Prompt) -> FilesDict:
        """
        Generates a new piece of code using the AI and step bundle based on the provided prompt.

        Parameters
        ----------
        prompt : str
            A string prompt that guides the code generation process.

        Returns
        -------
        FilesDict
            An instance of the `FilesDict` class containing the generated code.
        """

        files_dict = self.code_gen_fn(
            self.ai, prompt, self.memory, self.preprompts_holder
        )
        entrypoint = gen_entrypoint(
            self.ai, prompt, files_dict, self.memory, self.preprompts_holder
        )
        combined_dict = {**files_dict, **entrypoint}
        files_dict = FilesDict(combined_dict)
        files_dict = self.process_code_fn(
            self.ai,
            self.execution_env,
            files_dict,
            preprompts_holder=self.preprompts_holder,
            prompt=prompt,
            memory=self.memory,
        )
        return files_dict

    def improve(
        self,
        files_dict: FilesDict,
        prompt: Prompt,
        execution_command: Optional[str] = None,
        diff_timeout=3,
    ) -> FilesDict:
        """
        Improves an existing piece of code using the AI and step bundle based on the provided prompt.

        Parameters
        ----------
        files_dict : FilesDict
            An instance of `FilesDict` containing the code to be improved.
        prompt : str
            A string prompt that guides the code improvement process.
        execution_command : str, optional
            An optional command to execute the code. If not provided, the default execution command is used.

        Returns
        -------
        FilesDict
            An instance of the `FilesDict` class containing the improved code.
        """

        files_dict = self.improve_fn(
            self.ai,
            prompt,
            files_dict,
            self.memory,
            self.preprompts_holder,
            diff_timeout=diff_timeout,
        )
        # entrypoint = gen_entrypoint(
        #     self.ai, prompt, files_dict, self.memory, self.preprompts_holder
        # )
        # combined_dict = {**files_dict, **entrypoint}
        # files_dict = FilesDict(combined_dict)
        # files_dict = self.process_code_fn(
        #     self.ai,
        #     self.execution_env,
        #     files_dict,
        #     preprompts_holder=self.preprompts_holder,
        #     prompt=prompt,
        #     memory=self.memory,
        # )

        return files_dict


================================================
FILE: gpt_engineer/applications/cli/collect.py
================================================
"""
Module `collect` - Data Handling and RudderStack Integration

This module provides functionalities to handle and send learning data to RudderStack
for the purpose of analysis and to improve the gpt-engineer system. The data is sent
only when the user gives consent to share.

Functions:
    send_learning(learning): Sends learning data to RudderStack.
    collect_learnings(prompt, model, temperature, config, memory, review): Processes and sends learning data.
    collect_and_send_human_review(prompt, model, temperature, config, memory): Collects human feedback and sends it.

Dependencies:
    hashlib: For generating SHA-256 hash.
    typing: For type annotations.
    gpt_engineer.core: Core functionalities of gpt-engineer.
    gpt_engineer.cli.learning: Handles the extraction of learning data.

Notes:
    Data sent to RudderStack is not shared with third parties and is used solely to
    improve gpt-engineer and allow it to handle a broader range of use cases.
    Consent logic is in gpt_engineer/learning.py.
"""

from typing import Tuple

from gpt_engineer.applications.cli.learning import (
    Learning,
    Review,
    extract_learning,
    human_review_input,
)
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.prompt import Prompt


def send_learning(learning: Learning):
    """
    Send the learning data to RudderStack for analysis.

    Parameters
    ----------
    learning : Learning
        An instance of the Learning class containing the data to be sent.

    Notes
    -----
    This function is only called if consent is given to share data.
    Data is not shared to a third party. It is used with the sole purpose of
    improving gpt-engineer, and letting it handle more use cases.
    Consent logic is in gpt_engineer/learning.py.
    """
    import rudderstack.analytics as rudder_analytics

    rudder_analytics.write_key = "2Re4kqwL61GDp7S8ewe6K5dbogG"
    rudder_analytics.dataPlaneUrl = "https://gptengineerezm.dataplane.rudderstack.com"

    rudder_analytics.track(
        user_id=learning.session,
        event="learning",
        properties=learning.to_dict(),  # type: ignore
    )


def collect_learnings(
    prompt: Prompt,
    model: str,
    temperature: float,
    config: any,
    memory: DiskMemory,
    review: Review,
):
    """
    Collect the learning data and send it to RudderStack for analysis.

    Parameters
    ----------
    prompt : str
        The initial prompt or question that was provided to the model.
    model : str
        The name of the model used for generating the response.
    temperature : float
        The temperature setting used in the model's response generation.
    config : any
        Configuration parameters used for the learning session.
    memory : DiskMemory
        An instance of DiskMemory for storing and retrieving data.
    review : Review
        An instance of Review containing human feedback on the model's response.

    Notes
    -----
    This function attempts to send the learning data to RudderStack. If the data size exceeds
    the maximum allowed size, it trims the data and retries sending it.
    """
    learnings = extract_learning(prompt, model, temperature, config, memory, review)
    try:
        send_learning(learnings)
    except RuntimeError:
        # try to remove some parts of learning that might be too big
        # rudderstack max event size is 32kb
        max_size = 32 << 10  # 32KB in bytes
        current_size = len(learnings.to_json().encode("utf-8"))  # get size in bytes

        overflow = current_size - max_size

        # Add some extra characters for the "[REMOVED...]" string and for safety margin
        remove_length = overflow + len(f"[REMOVED {overflow} CHARACTERS]") + 100

        learnings.logs = (
            learnings.logs[:-remove_length]
            + f"\n\n[REMOVED {remove_length} CHARACTERS]"
        )

        print(
            "WARNING: learning too big, removing some parts. "
            "Please report if this results in a crash."
        )
        try:
            send_learning(learnings)
        except RuntimeError:
            print(
                "Sending learnings crashed despite truncation. Progressing without saving learnings."
            )


# def steps_file_hash():
#     """
#     Compute the SHA-256 hash of the steps file.
#
#     Returns
#     -------
#     str
#         The SHA-256 hash of the steps file.
#     """
#     with open(steps.__file__, "r") as f:
#         content = f.read()
#         return hashlib.sha256(content.encode("utf-8")).hexdigest()


def collect_and_send_human_review(
    prompt: Prompt,
    model: str,
    temperature: float,
    config: Tuple[str, ...],
    memory: DiskMemory,
):
    """
    Collects human feedback on the code and sends it for analysis.

    Parameters
    ----------
    prompt : str
        The initial prompt or question that was provided to the model.
    model : str
        The name of the model used for generating the response.
    temperature : float
        The temperature setting used in the model's response generation.
    config : Tuple[str, ...]
        Configuration parameters used for the learning session.
    memory : DiskMemory
        An instance of DiskMemory for storing and retrieving data.

    Returns
    -------
    None

    Notes
    -----
    This function prompts the user for a review of the generated or improved code using the
    `human_review_input` function. If a valid review is provided, it's serialized to JSON format
    and stored within the database's memory under the "review" key.
    """

    review = human_review_input()
    if review:
        collect_learnings(prompt, model, temperature, config, memory, review)


================================================
FILE: gpt_engineer/applications/cli/file_selector.py
================================================
"""
file_selector.py

This module offers interactive file selection for projects. Leveraging a terminal-based,
tree-structured display, users can navigate and select files for editing or processing.
It integrates with system editors for direct file modification and supports saving
selections for later use. Designed for efficient workflow enhancement in file-intensive
environments, it offers customizable file filtering and seamless editor integration.

Key Components:
- FileSelector: Manages file selection and interaction.
- DisplayablePath: Provides a structured view of file paths.

Usage:
Typically used in project setup or management phases for selecting specific files.
It operates within the GPT-Engineer environment, relying on core functionalities for
file handling and persistence.
"""

import fnmatch
import os
import subprocess

from pathlib import Path
from typing import Any, Dict, Generator, List, Union

import toml

from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.default.paths import metadata_path
from gpt_engineer.core.files_dict import FilesDict
from gpt_engineer.core.git import filter_by_gitignore, is_git_repo


class FileSelector:
    """
    Manages file selection and interaction within a project directory.

    This class provides methods to interactively select files from the terminal,
    save selections for later use, and integrate with system editors for direct
    file modification.

    Attributes
    ----------
    IGNORE_FOLDERS : set
        A set of directory names to ignore during file selection.
    FILE_LIST_NAME : str
        The name of the file that stores the selected files list.
    COMMENT : str
        The comment string to be added to the top of the file selection list.
    """

    IGNORE_FOLDERS = {"site-packages", "node_modules", "venv", "__pycache__"}
    FILE_LIST_NAME = "file_selection.toml"
    COMMENT = (
        "# Remove '#' to select a file or turn off linting.\n\n"
        "# Linting with BLACK (Python) enhances code suggestions from LLMs. "
        "To disable linting, uncomment the relevant option in the linting settings.\n\n"
        "# gpt-engineer can only read selected files. "
        "Including irrelevant files will degrade performance, "
        "cost additional tokens and potentially overflow token limit.\n\n"
    )
    LINTING_STRING = '[linting]\n# "linting" = "off"\n\n'
    is_linting = True

    def __init__(self, project_path: Union[str, Path]):
        """
        Initializes the FileSelector with a given project path.

        Parameters
        ----------
        project_path : Union[str, Path]
            The path to the project directory where file selection is to be performed.
        """
        self.project_path = project_path
        self.metadata_db = DiskMemory(metadata_path(self.project_path))
        self.toml_path = self.metadata_db.path / self.FILE_LIST_NAME

    def ask_for_files(self, skip_file_selection=False) -> tuple[FilesDict, bool]:
        """
        Prompts the user to select files for context improvement.

        This method supports selection from the terminal or using a previously saved list.
        In test mode, it retrieves files from a predefined TOML configuration.

        Returns
        -------
        FilesDict
            A dictionary with file paths as keys and file contents as values.
        """

        if os.getenv("GPTE_TEST_MODE") or skip_file_selection:
            # In test mode, retrieve files from a predefined TOML configuration
            # also get from toml if skip_file_selector is active
            assert self.FILE_LIST_NAME in self.metadata_db
            selected_files = self.get_files_from_toml(self.project_path, self.toml_path)
        else:
            # Otherwise, use the editor file selector for interactive selection
            if self.FILE_LIST_NAME in self.metadata_db:
                print(
                    f"File list detected at {self.toml_path}. Edit or delete it if you want to select new files."
                )
                selected_files = self.editor_file_selector(self.project_path, False)
            else:
                selected_files = self.editor_file_selector(self.project_path, True)

        content_dict = {}
        for file_path in selected_files:
            # selected files contains paths that are relative to the project path
            try:
                # to open the file we need the path from the cwd
                with open(
                    Path(self.project_path) / file_path, "r", encoding="utf-8"
                ) as content:
                    content_dict[str(file_path)] = content.read()
            except FileNotFoundError:
                print(f"Warning: File not found {file_path}")
            except UnicodeDecodeError:
                print(f"Warning: File not UTF-8 encoded {file_path}, skipping")

        return FilesDict(content_dict), self.is_linting

    def editor_file_selector(
        self, input_path: Union[str, Path], init: bool = True
    ) -> List[str]:
        """
        Provides an interactive file selection interface using a .toml file.

        Parameters
        ----------
        input_path : Union[str, Path]
            The path where file selection is to be performed.
        init : bool, optional
            Indicates whether to initialize the .toml file with the file tree.

        Returns
        -------
        List[str]
            A list of strings representing the paths of selected files.
        """

        root_path = Path(input_path)
        tree_dict = {}
        toml_file = DiskMemory(metadata_path(input_path)).path / "file_selection.toml"
        # Define the toml file path

        # Initialize .toml file with file tree if in initial state
        if init:
            tree_dict = {x: "selected" for x in self.get_current_files(root_path)}

            s = toml.dumps({"files": tree_dict})

            # add comments on all lines that match = "selected"
            s = "\n".join(
                [
                    "# " + line if line.endswith(' = "selected"') else line
                    for line in s.split("\n")
                ]
            )
            # Write to the toml file
            with open(toml_file, "w") as f:
                f.write(self.COMMENT)
                f.write(self.LINTING_STRING)
                f.write(s)

        else:
            # Load existing files from the .toml configuration
            all_files = self.get_current_files(root_path)
            s = toml.dumps({"files": {x: "selected" for x in all_files}})

            # get linting status from the toml file
            with open(toml_file, "r") as file:
                linting_status = toml.load(file)
            if (
                "linting" in linting_status
                and linting_status["linting"].get("linting", "").lower() == "off"
            ):
                self.is_linting = False
                self.LINTING_STRING = '[linting]\n"linting" = "off"\n\n'
                print("\nLinting is disabled")

            with open(toml_file, "r") as file:
                selected_files = toml.load(file)

            lines = s.split("\n")
            s = "\n".join(
                lines[:1]
                + [
                    line
                    if line.split(" = ")[0].strip('"') in selected_files["files"]
                    else "# " + line
                    for line in lines[1:]
                ]
            )

            # Write the merged list back to the .toml for user review and modification
            with open(toml_file, "w") as file:
                file.write(self.COMMENT)  # Ensure to write the comment
                file.write(self.LINTING_STRING)
                file.write(s)

        print(
            "Please select and deselect (add # in front) files, save it, and close it to continue..."
        )
        self.open_with_default_editor(
            toml_file
        )  # Open the .toml file in the default editor for user modification
        return self.get_files_from_toml(
            input_path, toml_file
        )  # Return the list of selected files after user edits

    def open_with_default_editor(self, file_path: Union[str, Path]):
        """
        Opens a file with the system's default text editor.

        Parameters
        ----------
        file_path : Union[str, Path]
            The path to the file to be opened in the text editor.
        """

        editors = [
            "gedit",
            "notepad",
            "nvim",
            "write",
            "nano",
            "vim",
            "emacs",
        ]  # Putting the beginner-friendly text editor forward
        chosen_editor = os.environ.get("EDITOR")

        # Try the preferred editor first, then fallback to common editors
        if chosen_editor:
            try:
                subprocess.run([chosen_editor, file_path])
                return
            except Exception:
                pass

        for editor in editors:
            try:
                subprocess.run([editor, file_path])
                return
            except Exception:
                continue
        print("No suitable text editor found. Please edit the file manually.")

    def is_utf8(self, file_path: Union[str, Path]) -> bool:
        """
        Checks if the file at the given path is UTF-8 encoded.

        Parameters
        ----------
        file_path : Union[str, Path]
            The path to the file to be checked.

        Returns
        -------
        bool
            True if the file is UTF-8 encoded, False otherwise.
        """

        try:
            with open(file_path, "rb") as file:
                file.read().decode("utf-8")
                return True
        except UnicodeDecodeError:
            return False

    def get_files_from_toml(
        self, input_path: Union[str, Path], toml_file: Union[str, Path]
    ) -> List[str]:
        """
        Retrieves a list of selected files from a .toml configuration file.

        Parameters
        ----------
        input_path : Union[str, Path]
            The path where file selection was performed.
        toml_file : Union[str, Path]
            The path to the .toml file containing the file selection.

        Returns
        -------
        List[str]
            A list of strings representing the paths of selected files.

        Raises
        ------
        Exception
            If no files are selected in the .toml file.
        """
        selected_files = []
        edited_tree = toml.load(toml_file)  # Load the edited .toml file

        # check if users have disabled linting or not
        if (
            "linting" in edited_tree
            and edited_tree["linting"].get("linting", "").lower() == "off"
        ):
            self.is_linting = False
            print("\nLinting is disabled")
        else:
            self.is_linting = True

        # Iterate through the files in the .toml and append selected files to the list
        for file, _ in edited_tree["files"].items():
            selected_files.append(file)

        # Ensure that at least one file is selected, or raise an exception
        if not selected_files:
            raise Exception(
                "No files were selected. Please select at least one file to proceed."
            )

        print(f"\nYou have selected the following files:\n{input_path}")

        project_path = Path(input_path).resolve()
        selected_paths = set(
            project_path.joinpath(file).resolve(strict=False) for file in selected_files
        )

        for displayable_path in DisplayablePath.make_tree(project_path):
            if displayable_path.path in selected_paths:
                p = displayable_path
                while p.parent and p.parent.path not in selected_paths:
                    selected_paths.add(p.parent.path)
                    p = p.parent

        try:
            for displayable_path in DisplayablePath.make_tree(project_path):
                if displayable_path.path in selected_paths:
                    print(displayable_path.displayable())

        except FileNotFoundError:
            print("Specified path does not exist: ", project_path)
        except Exception as e:
            print("An error occurred while trying to display the file tree:", e)

        print("\n")
        return selected_files

    def merge_file_lists(
        self, existing_files: Dict[str, Any], new_files: Dict[str, Any]
    ) -> Dict[str, Any]:
        """
        Merges two lists of files, preserving the selection status.

        Parameters
        ----------
        existing_files : Dict[str, Any]
            The dictionary of existing files with their properties.
        new_files : Dict[str, Any]
            The dictionary of new files with their properties.

        Returns
        -------
        Dict[str, Any]
            The updated dictionary of files after merging.
        """
        # Update the existing files with any new files or changes
        for file, properties in new_files.items():
            if file not in existing_files:
                existing_files[file] = properties  # Add new files as unselected
            # If you want to update other properties of existing files, you can do so here

        return existing_files

    def should_filter_file(self, file_path: Path, filters: List[str]) -> bool:
        """
        Determines if a file should be ignored based on .gitignore rules.
        """
        for f in filters:
            if fnmatch.fnmatchcase(str(file_path), f):
                return True
        return False

    def get_current_files(self, project_path: Union[str, Path]) -> List[str]:
        """
        Generates a list of all files in the project directory. Will use .gitignore files if project_path is a git repository.

        Parameters
        ----------
        project_path : Union[str, Path]
            The path to the project directory.

        Returns
        -------
        List[str]
            A list of strings representing the relative paths of all files in the project directory.
        """
        all_files = []
        project_path = Path(
            project_path
        ).resolve()  # Ensure path is absolute and resolved

        file_list = project_path.glob("**/*")

        for path in file_list:  # Recursively list all files
            if path.is_file():
                relpath = path.relative_to(project_path)
                parts = relpath.parts
                if any(part.startswith(".") for part in parts):
                    continue  # Skip hidden files
                if any(part in self.IGNORE_FOLDERS for part in parts):
                    continue
                if relpath.name == "prompt":
                    continue  # Skip files named 'prompt'

                all_files.append(str(relpath))

        if is_git_repo(project_path) and "projects" not in project_path.parts:
            all_files = filter_by_gitignore(project_path, all_files)

        return sorted(all_files, key=lambda x: Path(x).as_posix())


class DisplayablePath(object):
    """
    Represents and displays a file system path in a tree-like structure.

    This class is used to visually represent the structure of directories and files
    in a way that is similar to a file explorer's tree view.
    """

    display_filename_prefix_middle = "├── "
    display_filename_prefix_last = "└── "
    display_parent_prefix_middle = "    "
    display_parent_prefix_last = "│   "

    def __init__(
        self, path: Union[str, Path], parent_path: "DisplayablePath", is_last: bool
    ):
        """
        Initializes a DisplayablePath object with a given path and parent.

        Parameters
        ----------
        path : Union[str, Path]
            The file system path to be displayed.
        parent_path : DisplayablePath
            The parent path in the tree structure.
        is_last : bool
            Indicates whether this is the last sibling in the tree structure.
        """
        self.depth = 0
        self.path = Path(str(path))
        self.parent = parent_path
        self.is_last = is_last
        if self.parent:
            self.depth = self.parent.depth + 1  # Increment depth if it has a parent

    @property
    def display_name(self) -> str:
        """
        Get the display name of the file or directory.
        """
        if self.path.is_dir():
            return self.path.name + "/"
        return self.path.name

    @classmethod
    def make_tree(
        cls, root: Union[str, Path], parent=None, is_last=False, criteria=None
    ) -> Generator["DisplayablePath", None, None]:
        """
        Creates a tree of DisplayablePath objects from a root directory.

        Parameters
        ----------
        root : Union[str, Path]
            The root directory from which to start creating the tree.
        parent : DisplayablePath, optional
            The parent path in the tree structure.
        is_last : bool, optional
            Indicates whether this is the last sibling in the tree structure.
        criteria : callable, optional
            A function to filter the paths included in the tree.

        Yields
        ------
        DisplayablePath
            The next DisplayablePath object in the tree.
        """
        root = Path(str(root))  # Ensure root is a Path object
        criteria = criteria or cls._default_criteria
        displayable_root = cls(root, parent, is_last)
        yield displayable_root

        if root.is_dir():  # Check if root is a directory before iterating
            children = sorted(
                list(path for path in root.iterdir() if criteria(path)),
                key=lambda s: str(s).lower(),
            )
            count = 1
            for path in children:
                is_last = count == len(children)
                yield from cls.make_tree(
                    path, parent=displayable_root, is_last=is_last, criteria=criteria
                )
                count += 1

    @classmethod
    def _default_criteria(cls, path: Path) -> bool:
        """
        The default criteria function to filter the paths.
        """
        return True

    def displayable(self) -> str:
        """
        Returns a string representation of the path for display in a tree-like structure.

        Returns
        -------
        str
            The displayable string representation of the file or directory.
        """
        if self.parent is None:
            return self.display_name

        _filename_prefix = (
            self.display_filename_prefix_last
            if self.is_last
            else self.display_filename_prefix_middle
        )

        parts = ["{!s} {!s}".format(_filename_prefix, self.display_name)]

        parent = self.parent
        while parent and parent.parent is not None:
            parts.append(
                self.display_parent_prefix_middle
                if parent.is_last
                else self.display_parent_prefix_last
            )
            parent = parent.parent

        return "".join(reversed(parts))  # Assemble the parts into the final string


================================================
FILE: gpt_engineer/applications/cli/learning.py
================================================
"""
The `learning` module is designed to facilitate the collection and storage of user feedback on the outputs generated by the GPT Engineer tool. It provides mechanisms for obtaining user consent, capturing user reviews, and storing this information for future analysis and enhancement of the tool's performance.

Classes
-------
Review : dataclass
    Represents a user's review of the generated code, including whether it ran, was perfect, was useful, and any additional comments.
Learning : dataclass
    Encapsulates the metadata and feedback collected during a session of using the GPT Engineer tool, including the prompt, model, temperature, configuration, logs, session identifier, user review, and timestamp.

Functions
---------
human_review_input() -> Optional[Review]
    Interactively gathers feedback from the user regarding the performance of generated code and returns a Review instance.
check_collection_consent() -> bool
    Checks if the user has previously given consent to store their data and, if not, asks for it.
ask_collection_consent() -> bool
    Prompts the user for consent to store their data for the purpose of improving GPT Engineer.
extract_learning(prompt: Prompt, model: str, temperature: float, config: Tuple[str, ...], memory: DiskMemory, review: Review) -> Learning
    Extracts feedback and session details to create a Learning instance based on the provided parameters.
get_session() -> str
    Retrieves a unique identifier for the current user session, creating one if it does not exist.

Constants
---------
TERM_CHOICES : tuple
    Terminal color choices for user interactive prompts, formatted with termcolor for readability.
"""

import json
import random
import tempfile

from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Optional, Tuple

from dataclasses_json import dataclass_json
from termcolor import colored

from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.prompt import Prompt


@dataclass_json
@dataclass
class Review:
    """
    A dataclass that represents a user's review of the generated code.

    Attributes
    ----------
    ran : Optional[bool]
        Indicates whether the generated code ran without errors.
    perfect : Optional[bool]
        Indicates whether the generated code met all the user's requirements.
    works : Optional[bool]
        Indicates whether the generated code was useful, even if not perfect.
    comments : str
        Any additional comments provided by the user.
    raw : str
        A raw string representation of the user's responses.
    """

    ran: Optional[bool]
    perfect: Optional[bool]
    works: Optional[bool]
    comments: str
    raw: str


@dataclass_json
@dataclass
class Learning:
    """
    A dataclass that encapsulates the learning data collected during a GPT Engineer session.

    Attributes
    ----------
    prompt : str
        A JSON string representing the prompt provided to GPT Engineer.
    model : str
        The name of the model used during the session.
    temperature : float
        The temperature setting used for the model's responses.
    config : str
        A JSON string representing the configuration settings for the session.
    logs : str
        A JSON string representing the logs of the session.
    session : str
        A unique identifier for the user session.
    review : Optional[Review]
        The user's review of the generated code.
    timestamp : str
        The UTC timestamp when the learning data was created.
    version : str
        The version of the learning data schema.
    """

    prompt: str
    model: str
    temperature: float
    config: str
    logs: str
    session: str
    review: Optional[Review]
    timestamp: str = field(default_factory=lambda: datetime.utcnow().isoformat())
    version: str = "0.3"


TERM_CHOICES = (
    colored("y", "green")
    + "/"
    + colored("n", "red")
    + "/"
    + colored("u", "yellow")
    + "(ncertain): "
)


def human_review_input() -> Optional[Review]:
    """
    Interactively prompts the user to review the generated code and returns their feedback encapsulated in a Review object.

    This function will first check if the user has given consent to collect their feedback. If consent is given, it will ask the user a series of questions about the generated code's performance and capture their responses.

    Returns
    -------
    Optional[Review]
        A Review object containing the user's feedback, or None if consent is not given.
    """
    print()
    if not check_collection_consent():
        return None
    print()
    print(
        colored("To help gpt-engineer learn, please answer 3 questions:", "light_green")
    )
    print()

    ran = input("Did the generated code run at all? " + TERM_CHOICES)
    ran = ask_for_valid_input(ran)

    if ran == "y":
        perfect = input(
            "Did the generated code do everything you wanted? " + TERM_CHOICES
        )
        perfect = ask_for_valid_input(perfect)

        if perfect != "y":
            useful = input("Did the generated code do anything useful? " + TERM_CHOICES)
            useful = ask_for_valid_input(useful)
        else:
            useful = ""
    else:
        perfect = ""
        useful = ""

    if perfect != "y":
        comments = input(
            "If you have time, please explain what was not working "
            + colored("(ok to leave blank)\n", "light_green")
        )
    else:
        comments = ""

    return Review(
        raw=", ".join([ran, perfect, useful]),
        ran={"y": True, "n": False, "u": None, "": None}[ran],
        works={"y": True, "n": False, "u": None, "": None}[useful],
        perfect={"y": True, "n": False, "u": None, "": None}[perfect],
        comments=comments,
    )


def ask_for_valid_input(ran):
    while ran not in ("y", "n", "u"):
        ran = input("Invalid input. Please enter y, n, or u: ")
    return ran


def check_collection_consent() -> bool:
    """
    Checks if the user has previously given consent to store their data for feedback collection.

    This function looks for a file that stores the user's consent status. If the file exists and contains 'true', consent is assumed. If the file does not exist or does not contain 'true', the function will prompt the user for consent.

    Returns
    -------
    bool
        True if the user has given consent, False otherwise.
    """
    path = Path(".gpte_consent")
    if path.exists() and path.read_text() == "true":
        return True
    else:
        return ask_collection_consent()


def ask_collection_consent() -> bool:
    """
    Asks the user for their consent to store their data for the purpose of improving the GPT Engineer tool.

    The user's response is recorded in a file for future reference. If the user consents, the function will write 'true' to the file. If the user does not consent, no data will be collected, and the function will not modify the file.

    Returns
    -------
    bool
        True if the user consents, False otherwise.
    """
    answer = input(
        "Is it ok if we store your prompts to help improve GPT Engineer? (y/n)"
    )
    while answer.lower() not in ("y", "n"):
        answer = input("Invalid input. Please enter y or n: ")

    if answer.lower() == "y":
        path = Path(".gpte_consent")
        path.write_text("true")
        print(colored("Thank you️", "light_green"))
        print()
        print(
            "(If you no longer wish to participate in data collection, delete the file .gpte_consent)"
        )
        return True
    else:
        print(
            colored(
                "No worries! GPT Engineer will not collect your prompts. ❤️",
                "light_green",
            )
        )
        return False


def extract_learning(
    prompt: Prompt,
    model: str,
    temperature: float,
    config: Tuple[str, ...],
    memory: DiskMemory,
    review: Review,
) -> Learning:
    """
    Constructs a Learning object containing the session's metadata and user feedback.

    Parameters
    ----------
    prompt : str
        The initial prompt provided to the GPT Engineer.
    model : str
        The name of the model used during the session.
    temperature : float
        The temperature setting used for the model's responses.
    config : Tuple[str, ...]
        A tuple representing the configuration settings for the session.
    memory : DiskMemory
        An object representing the disk memory used during the session.
    review : Review
        The user's review of the generated code.

    Returns
    -------
    Learning
        An instance of Learning containing all the session details and user feedback.
    """
    return Learning(
        prompt=prompt.to_json(),
        model=model,
        temperature=temperature,
        config=json.dumps(config),
        session=get_session(),
        logs=memory.to_json(),
        review=review,
    )


def get_session() -> str:
    """
    Retrieves or generates a unique identifier for the current user session.

    This function attempts to read a unique user ID from a temporary file. If the file does not exist, it generates a new random ID, writes it to the file, and returns it. This ID is used to uniquely identify the user's session.

    Returns
    -------
    str
        A unique identifier for the user session.
    """
    path = Path(tempfile.gettempdir()) / "gpt_engineer_user_id.txt"

    try:
        if path.exists():
            user_id = path.read_text()
        else:
            # random uuid:
            user_id = str(random.randint(0, 2**32))
            path.write_text(user_id)
        return user_id
    except IOError:
        return "ephemeral_" + str(random.randint(0, 2**32))


================================================
FILE: gpt_engineer/applications/cli/main.py
================================================
"""
Entrypoint for the CLI tool.

This module serves as the entry point for a command-line interface (CLI) tool.
It is designed to interact with OpenAI's language models.
The module provides functionality to:
- Load necessary environment variables,
- Configure various parameters for the AI interaction,
- Manage the generation or improvement of code projects.

Main Functionality
------------------
- Load environment variables required for OpenAI API interaction.
- Parse user-specified parameters for project configuration and AI behavior.
- Facilitate interaction with AI models, databases, and archival processes.

Parameters
----------
None

Notes
-----
- The `OPENAI_API_KEY` must be set in the environment or provided in a `.env` file within the working directory.
- The default project path is `projects/example`.
- When using the `azure_endpoint` parameter, provide the Azure OpenAI service endpoint URL.
"""

import difflib
import json
import logging
import os
import platform
import subprocess
import sys

from pathlib import Path

import openai
import typer

from dotenv import load_dotenv
from langchain.globals import set_llm_cache
from langchain_community.cache import SQLiteCache
from termcolor import colored

from gpt_engineer.applications.cli.cli_agent import CliAgent
from gpt_engineer.applications.cli.collect import collect_and_send_human_review
from gpt_engineer.applications.cli.file_selector import FileSelector
from gpt_engineer.core.ai import AI, ClipboardAI
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.default.file_store import FileStore
from gpt_engineer.core.default.paths import PREPROMPTS_PATH, memory_path
from gpt_engineer.core.default.steps import (
    execute_entrypoint,
    gen_code,
    handle_improve_mode,
    improve_fn as improve_fn,
)
from gpt_engineer.core.files_dict import FilesDict
from gpt_engineer.core.git import stage_uncommitted_to_git
from gpt_engineer.core.preprompts_holder import PrepromptsHolder
from gpt_engineer.core.prompt import Prompt
from gpt_engineer.tools.custom_steps import clarified_gen, lite_gen, self_heal

app = typer.Typer(
    context_settings={"help_option_names": ["-h", "--help"]}
)  # creates a CLI app


def load_env_if_needed():
    """
    Load environment variables if the OPENAI_API_KEY is not already set.

    This function checks if the OPENAI_API_KEY environment variable is set,
    and if not, it attempts to load it from a .env file in the current working
    directory. It then sets the openai.api_key for use in the application.
    """
    # We have all these checks for legacy reasons...
    if os.getenv("OPENAI_API_KEY") is None:
        load_dotenv()
    if os.getenv("OPENAI_API_KEY") is None:
        load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"))

    openai.api_key = os.getenv("OPENAI_API_KEY")

    if os.getenv("ANTHROPIC_API_KEY") is None:
        load_dotenv()
    if os.getenv("ANTHROPIC_API_KEY") is None:
        load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"))


def concatenate_paths(base_path, sub_path):
    # Compute the relative path from base_path to sub_path
    relative_path = os.path.relpath(sub_path, base_path)

    # If the relative path is not in the parent directory, use the original sub_path
    if not relative_path.startswith(".."):
        return sub_path

    # Otherwise, concatenate base_path and sub_path
    return os.path.normpath(os.path.join(base_path, sub_path))


def load_prompt(
    input_repo: DiskMemory,
    improve_mode: bool,
    prompt_file: str,
    image_directory: str,
    entrypoint_prompt_file: str = "",
) -> Prompt:
    """
    Load or request a prompt from the user based on the mode.

    Parameters
    ----------
    input_repo : DiskMemory
        The disk memory object where prompts and other data are stored.
    improve_mode : bool
        Flag indicating whether the application is in improve mode.

    Returns
    -------
    str
        The loaded or inputted prompt.
    """

    if os.path.isdir(prompt_file):
        raise ValueError(
            f"The path to the prompt, {prompt_file}, already exists as a directory. No prompt can be read from it. Please specify a prompt file using --prompt_file"
        )
    prompt_str = input_repo.get(prompt_file)
    if prompt_str:
        print(colored("Using prompt from file:", "green"), prompt_file)
        print(prompt_str)
    else:
        if not improve_mode:
            prompt_str = input(
                "\nWhat application do you want gpt-engineer to generate?\n"
            )
        else:
            prompt_str = input("\nHow do you want to improve the application?\n")

    if entrypoint_prompt_file == "":
        entrypoint_prompt = ""
    else:
        full_entrypoint_prompt_file = concatenate_paths(
            input_repo.path, entrypoint_prompt_file
        )
        if os.path.isfile(full_entrypoint_prompt_file):
            entrypoint_prompt = input_repo.get(full_entrypoint_prompt_file)

        else:
            raise ValueError("The provided file at --entrypoint-prompt does not exist")

    if image_directory == "":
        return Prompt(prompt_str, entrypoint_prompt=entrypoint_prompt)

    full_image_directory = concatenate_paths(input_repo.path, image_directory)
    if os.path.isdir(full_image_directory):
        if len(os.listdir(full_image_directory)) == 0:
            raise ValueError("The provided --image_directory is empty.")
        image_repo = DiskMemory(full_image_directory)
        return Prompt(
            prompt_str,
            image_repo.get(".").to_dict(),
            entrypoint_prompt=entrypoint_prompt,
        )
    else:
        raise ValueError("The provided --image_directory is not a directory.")


def get_preprompts_path(use_custom_preprompts: bool, input_path: Path) -> Path:
    """
    Get the path to the preprompts, using custom ones if specified.

    Parameters
    ----------
    use_custom_preprompts : bool
        Flag indicating whether to use custom preprompts.
    input_path : Path
        The path to the project directory.

    Returns
    -------
    Path
        The path to the directory containing the preprompts.
    """
    original_preprompts_path = PREPROMPTS_PATH
    if not use_custom_preprompts:
        return original_preprompts_path

    custom_preprompts_path = input_path / "preprompts"
    if not custom_preprompts_path.exists():
        custom_preprompts_path.mkdir()

    for file in original_preprompts_path.glob("*"):
        if not (custom_preprompts_path / file.name).exists():
            (custom_preprompts_path / file.name).write_text(file.read_text())
    return custom_preprompts_path


def compare(f1: FilesDict, f2: FilesDict):
    def colored_diff(s1, s2):
        lines1 = s1.splitlines()
        lines2 = s2.splitlines()

        diff = difflib.unified_diff(lines1, lines2, lineterm="")

        RED = "\033[38;5;202m"
        GREEN = "\033[92m"
        RESET = "\033[0m"

        colored_lines = []
        for line in diff:
            if line.startswith("+"):
                colored_lines.append(GREEN + line + RESET)
            elif line.startswith("-"):
                colored_lines.append(RED + line + RESET)
            else:
                colored_lines.append(line)

        return "\n".join(colored_lines)

    for file in sorted(set(f1) | set(f2)):
        diff = colored_diff(f1.get(file, ""), f2.get(file, ""))
        if diff:
            print(f"Changes to {file}:")
            print(diff)


def prompt_yesno() -> bool:
    TERM_CHOICES = colored("y", "green") + "/" + colored("n", "red") + " "
    while True:
        response = input(TERM_CHOICES).strip().lower()
        if response in ["y", "yes"]:
            return True
        if response in ["n", "no"]:
            break
        print("Please respond with 'y' or 'n'")


def get_system_info():
    system_info = {
        "os": platform.system(),
        "os_version": platform.version(),
        "architecture": platform.machine(),
        "python_version": sys.version,
        "packages": format_installed_packages(get_installed_packages()),
    }
    return system_info


def get_installed_packages():
    try:
        result = subprocess.run(
            [sys.executable, "-m", "pip", "list", "--format=json"],
            capture_output=True,
            text=True,
        )
        packages = json.loads(result.stdout)
        return {pkg["name"]: pkg["version"] for pkg in packages}
    except Exception as e:
        return str(e)


def format_installed_packages(packages):
    return "\n".join([f"{name}: {version}" for name, version in packages.items()])


@app.command(
    help="""
        GPT-engineer lets you:

        \b
        - Specify a software in natural language
        - Sit back and watch as an AI writes and executes the code
        - Ask the AI to implement improvements
    """
)
def main(
    project_path: str = typer.Argument(".", help="path"),
    model: str = typer.Option(
        os.environ.get("MODEL_NAME", "gpt-4o"), "--model", "-m", help="model id string"
    ),
    temperature: float = typer.Option(
        0.1,
        "--temperature",
        "-t",
        help="Controls randomness: lower values for more focused, deterministic outputs",
    ),
    improve_mode: bool = typer.Option(
        False,
        "--improve",
        "-i",
        help="Improve an existing project by modifying the files.",
    ),
    lite_mode: bool = typer.Option(
        False,
        "--lite",
        "-l",
        help="Lite mode: run a generation using only the main prompt.",
    ),
    clarify_mode: bool = typer.Option(
        False,
        "--clarify",
        "-c",
        help="Clarify mode - discuss specification with AI before implementation.",
    ),
    self_heal_mode: bool = typer.Option(
        False,
        "--self-heal",
        "-sh",
        help="Self-heal mode - fix the code by itself when it fails.",
    ),
    azure_endpoint: str = typer.Option(
        "",
        "--azure",
        "-a",
        help="""Endpoint for your Azure OpenAI Service (https://xx.openai.azure.com).
            In that case, the given model is the deployment name chosen in the Azure AI Studio.""",
    ),
    use_custom_preprompts: bool = typer.Option(
        False,
        "--use-custom-preprompts",
        help="""Use your project's custom preprompts instead of the default ones.
          Copies all original preprompts to the project's workspace if they don't exist there.""",
    ),
    llm_via_clipboard: bool = typer.Option(
        False,
        "--llm-via-clipboard",
        help="Use the clipboard to communicate with the AI.",
    ),
    verbose: bool = typer.Option(
        False, "--verbose", "-v", help="Enable verbose logging for debugging."
    ),
    debug: bool = typer.Option(
        False, "--debug", "-d", help="Enable debug mode for debugging."
    ),
    prompt_file: str = typer.Option(
        "prompt",
        "--prompt_file",
        help="Relative path to a text file containing a prompt.",
    ),
    entrypoint_prompt_file: str = typer.Option(
        "",
        "--entrypoint_prompt",
        help="Relative path to a text file containing a file that specifies requirements for you entrypoint.",
    ),
    image_directory: str = typer.Option(
        "",
        "--image_directory",
        help="Relative path to a folder containing images.",
    ),
    use_cache: bool = typer.Option(
        False,
        "--use_cache",
        help="Speeds up computations and saves tokens when running the same prompt multiple times by caching the LLM response.",
    ),
    skip_file_selection: bool = typer.Option(
        False,
        "--skip-file-selection",
        "-s",
        help="Skip interactive file selection in improve mode and use the generated TOML file directly.",
    ),
    no_execution: bool = typer.Option(
        False,
        "--no_execution",
        help="Run setup but to not call LLM or write any code. For testing purposes.",
    ),
    sysinfo: bool = typer.Option(
        False,
        "--sysinfo",
        help="Output system information for debugging",
    ),
    diff_timeout: int = typer.Option(
        3,
        "--diff_timeout",
        help="Diff regexp timeout. Default: 3. Increase if regexp search timeouts.",
    ),
):
    """
    The main entry point for the CLI tool that generates or improves a project.

    This function sets up the CLI tool, loads environment variables, initializes
    the AI, and processes the user's request to generate or improve a project
    based on the provided arguments.

    Parameters
    ----------
    project_path : str
        The file path to the project directory.
    model : str
        The model ID string for the AI.
    temperature : float
        The temperature setting for the AI's responses.
    improve_mode : bool
        Flag indicating whether to improve an existing project.
    lite_mode : bool
        Flag indicating whether to run in lite mode.
    clarify_mode : bool
        Flag indicating whether to discuss specifications with AI before implementation.
    self_heal_mode : bool
        Flag indicating whether to enable self-healing mode.
    azure_endpoint : str
        The endpoint for Azure OpenAI services.
    use_custom_preprompts : bool
        Flag indicating whether to use custom preprompts.
    prompt_file : str
        Relative path to a text file containing a prompt.
    entrypoint_prompt_file: str
        Relative path to a text file containing a file that specifies requirements for you entrypoint.
    image_directory: str
        Relative path to a folder containing images.
    use_cache: bool
        Speeds up computations and saves tokens when running the same prompt multiple times by caching the LLM response.
    verbose : bool
        Flag indicating whether to enable verbose logging.
    skip_file_selection: bool
        Skip interactive file selection in improve mode and use the generated TOML file directly
    no_execution: bool
        Run setup but to not call LLM or write any code. For testing purposes.
    sysinfo: bool
        Flag indicating whether to output system information for debugging.

    Returns
    -------
    None
    """

    if debug:
        import pdb

        sys.excepthook = lambda *_: pdb.pm()

    if sysinfo:
        sys_info = get_system_info()
        for key, value in sys_info.items():
            print(f"{key}: {value}")
        raise typer.Exit()

    # Validate arguments
    if improve_mode and (clarify_mode or lite_mode):
        typer.echo("Error: Clarify and lite mode are not compatible with improve mode.")
        raise typer.Exit(code=1)

    # Set up logging
    logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO)
    if use_cache:
        set_llm_cache(SQLiteCache(database_path=".langchain.db"))
    if improve_mode:
        assert not (
            clarify_mode or lite_mode
        ), "Clarify and lite mode are not active for improve mode"

    load_env_if_needed()

    if llm_via_clipboard:
        ai = ClipboardAI()
    else:
        ai = AI(
            model_name=model,
            temperature=temperature,
            azure_endpoint=azure_endpoint,
        )

    path = Path(project_path)
    print("Running gpt-engineer in", path.absolute(), "\n")

    prompt = load_prompt(
        DiskMemory(path),
        improve_mode,
        prompt_file,
        image_directory,
        entrypoint_prompt_file,
    )

    # todo: if ai.vision is false and not llm_via_clipboard - ask if they would like to use gpt-4-vision-preview instead? If so recreate AI
    if not ai.vision:
        prompt.image_urls = None

    # configure generation function
    if clarify_mode:
        code_gen_fn = clarified_gen
    elif lite_mode:
        code_gen_fn = lite_gen
    else:
        code_gen_fn = gen_code

    # configure execution function
    if self_heal_mode:
        execution_fn = self_heal
    else:
        execution_fn = execute_entrypoint

    preprompts_holder = PrepromptsHolder(
        get_preprompts_path(use_custom_preprompts, Path(project_path))
    )

    memory = DiskMemory(memory_path(project_path))
    memory.archive_logs()

    execution_env = DiskExecutionEnv()
    agent = CliAgent.with_default_config(
        memory,
        execution_env,
        ai=ai,
        code_gen_fn=code_gen_fn,
        improve_fn=improve_fn,
        process_code_fn=execution_fn,
        preprompts_holder=preprompts_holder,
    )

    files = FileStore(project_path)
    if not no_execution:
        if improve_mode:
            files_dict_before, is_linting = FileSelector(project_path).ask_for_files(
                skip_file_selection=skip_file_selection
            )

            # lint the code
            if is_linting:
                files_dict_before = files.linting(files_dict_before)

            files_dict = handle_improve_mode(
                prompt, agent, memory, files_dict_before, diff_timeout=diff_timeout
            )
            if not files_dict or files_dict_before == files_dict:
                print(
                    f"No changes applied. Could you please upload the debug_log_file.txt in {memory.path}/logs folder in a github issue?"
                )

            else:
                print("\nChanges to be made:")
                compare(files_dict_before, files_dict)

                print()
                print(colored("Do you want to apply these changes?", "light_green"))
                if not prompt_yesno():
                    files_dict = files_dict_before

        else:
            files_dict = agent.init(prompt)
            # collect user feedback if user consents
            config = (code_gen_fn.__name__, execution_fn.__name__)
            collect_and_send_human_review(prompt, model, temperature, config, memory)

        stage_uncommitted_to_git(path, files_dict, improve_mode)

        files.push(files_dict)

    if ai.token_usage_log.is_openai_model():
        print("Total api cost: $ ", ai.token_usage_log.usage_cost())
    elif os.getenv("LOCAL_MODEL"):
        print("Total api cost: $ 0.0 since we are using local LLM.")
    else:
        print("Total tokens used: ", ai.token_usage_log.total_tokens())


if __name__ == "__main__":
    app()


================================================
FILE: gpt_engineer/benchmark/__init__.py
================================================


================================================
FILE: gpt_engineer/benchmark/__main__.py
================================================
"""
Main entry point for the benchmarking tool.

This module provides a command-line interface for running benchmarks using Typer.
It allows users to specify the path to an agent, the benchmark(s) to run, and other
options such as verbosity.

Functions
---------
get_agent : function
    Dynamically imports and returns the default configuration agent from the given path.

main : function
    The main function that runs the specified benchmarks with the given agent.
    Outputs the results to the console.

Attributes
----------
__name__ : str
    The standard boilerplate for invoking the main function when the script is executed.
"""
import importlib
import os.path
import sys

from typing import Annotated, Optional

import typer

from langchain.globals import set_llm_cache
from langchain_community.cache import SQLiteCache

from gpt_engineer.applications.cli.main import load_env_if_needed
from gpt_engineer.benchmark.bench_config import BenchConfig
from gpt_engineer.benchmark.benchmarks.load import get_benchmark
from gpt_engineer.benchmark.run import export_yaml_results, print_results, run

app = typer.Typer(
    context_settings={"help_option_names": ["-h", "--help"]}
)  # creates a CLI app


def get_agent(path):
    """
    Dynamically imports and returns the default configuration agent from the given path.

    Parameters
    ----------
    path : str
        The file path to the module containing the default configuration agent.

    Returns
    -------
    BaseAgent
        An instance of the imported default configuration agent.
    """
    # Dynamically import the python module at path
    sys.path.append(os.path.dirname(path))
    agent_module = importlib.import_module(path.replace("/", ".").replace(".py", ""))
    return agent_module.default_config_agent()


@app.command(
    help="""
        Run any benchmark(s) against the specified agent.

        \b
        Currently available benchmarks are: apps and mbpp
    """
)
def main(
    path_to_agent: Annotated[
        str,
        typer.Argument(
            help="python file that contains a function called 'default_config_agent'"
        ),
    ],
    bench_config: Annotated[
        str, typer.Argument(help="optional task name in benchmark")
    ] = os.path.join(os.path.dirname(__file__), "default_bench_config.toml"),
    yaml_output: Annotated[
        Optional[str],
        typer.Option(help="print results for each task", show_default=False),
    ] = None,
    verbose: Annotated[
        Optional[bool],
        typer.Option(help="print results for each task", show_default=False),
    ] = False,
    use_cache: Annotated[
        Optional[bool],
        typer.Option(
            help="Speeds up computations and saves tokens when running the same prompt multiple times by caching the LLM response.",
            show_default=False,
        ),
    ] = True,
):
    """
    The main function that runs the specified benchmarks with the given agent and outputs the results to the console.

    Parameters
    ----------
    path_to_agent : str
        The file path to the Python module that contains a function called 'default_config_agent'.
    bench_config : str, default=default_bench_config.toml
        Configuration file for choosing which benchmark problems to run. See default config for more details.
    yaml_output: Optional[str], default=None
        Pass a path to a yaml file to have results written to file.
    verbose : Optional[bool], default=False
        A flag to indicate whether to print results for each task.
    use_cache : Optional[bool], default=True
        Speeds up computations and saves tokens when running the same prompt multiple times by caching the LLM response.
    Returns
    -------
    None
    """
    if use_cache:
        set_llm_cache(SQLiteCache(database_path=".langchain.db"))
    load_env_if_needed()
    config = BenchConfig.from_toml(bench_config)
    print("using config file: " + bench_config)
    benchmarks = list()
    benchmark_results = dict()
    for specific_config_name in vars(config):
        specific_config = getattr(config, specific_config_name)
        if hasattr(specific_config, "active"):
            if specific_config.active:
                benchmarks.append(specific_config_name)

    for benchmark_name in benchmarks:
        benchmark = get_benchmark(benchmark_name, config)
        if len(benchmark.tasks) == 0:
            print(
                benchmark_name
                + " was skipped, since no tasks are specified. Increase the number of tasks in the config file at: "
                + bench_config
            )
            continue
        agent = get_agent(path_to_agent)

        results = run(agent, benchmark, verbose=verbose)
        print(
            f"\n--- Results for agent {path_to_agent}, benchmark: {benchmark_name} ---"
        )
        print_results(results)
        print()
        benchmark_results[benchmark_name] = {
            "detailed": [result.to_dict() for result in results]
        }
    if yaml_output is not None:
        export_yaml_results(yaml_output, benchmark_results, config.to_dict())


if __name__ == "__main__":
    typer.run(main)


================================================
FILE: gpt_engineer/benchmark/bench_config.py
================================================
from dataclasses import dataclass, field
from pathlib import Path

from tomlkit.items import Integer

from gpt_engineer.core.project_config import read_config


@dataclass
class AppsConfig:
    active: bool | None = True
    test_start_index: int | None = 0
    test_end_index: int | None = 1
    train_start_index: int | None = 0
    train_end_index: int | None = 0
    examples_per_problem: int | None = 10


@dataclass
class MbppConfig:
    active: bool | None = True
    test_len: int | None = 1
    train_len: int | None = 0


@dataclass
class GptmeConfig:
    active: bool | None = True


@dataclass
class BenchConfig:
    """Configuration for the GPT Engineer CLI and gptengineer.app via `gpt-engineer.toml`."""

    apps: AppsConfig = field(default_factory=AppsConfig)
    mbpp: MbppConfig = field(default_factory=MbppConfig)
    gptme: GptmeConfig = field(default_factory=GptmeConfig)

    @classmethod
    def from_toml(cls, config_file: Path | str):
        if isinstance(config_file, str):
            config_file = Path(config_file)
        config_dict = read_config(config_file)
        return cls.from_dict(config_dict)

    @classmethod
    def from_dict(cls, config_dict: dict):
        return cls(
            apps=AppsConfig(**config_dict.get("apps", {})),
            mbpp=MbppConfig(**config_dict.get("mbpp", {})),
            gptme=GptmeConfig(**config_dict.get("gptme", {})),
        )

    @staticmethod
    def recursive_resolve(data_dict):
        for key, value in data_dict.items():
            if isinstance(value, Integer):
                data_dict[key] = int(value)
            elif isinstance(value, dict):
                BenchConfig.recursive_resolve(value)

    def to_dict(self):
        dict_config = {
            benchmark_name: {key: val for key, val in spec_config.__dict__.items()}
            for benchmark_name, spec_config in self.__dict__.items()
        }
        BenchConfig.recursive_resolve(dict_config)

        return dict_config


================================================
FILE: gpt_engineer/benchmark/benchmarks/apps/load.py
================================================
"""
Module for loading APPS evaluation tasks.

This module provides functionality to load tasks for evaluating GPT-based models
on smaller, more focused tasks. It defines a set of tasks with predefined prompts
and assertions to benchmark the performance of AI models.

Functions
---------
load_apps : function
    Loads the APPS benchmark, which consists of a series coding problems.
"""
from pathlib import Path
from subprocess import TimeoutExpired
from typing import Union

from datasets import Dataset, DatasetDict, load_dataset, load_from_disk

from gpt_engineer.benchmark.bench_config import AppsConfig
from gpt_engineer.benchmark.benchmarks.apps.problem import Problem
from gpt_engineer.benchmark.types import Assertable, Benchmark, Task
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv
from gpt_engineer.core.files_dict import FilesDict
from gpt_engineer.core.prompt import Prompt

DATASET_PATH = Path(__file__).parent / "dataset"


class AppsAssertion:
    def __init__(self, expected: str, command: str):
        self.expected_output = self._format(expected)
        self.command = command

    def evaluate(self, assertable: Assertable) -> bool:
        # Create new execution environment for every run to avoid side effects
        env = DiskExecutionEnv()
        env.upload(assertable.files)
        pro = env.popen(self.command)
        try:
            stdout, stderr = pro.communicate(timeout=2)
            stdout, stderr = stdout.decode("utf-8"), stderr.decode("utf-8")
        except TimeoutExpired:
            print("Execution Timeout")
            return False

        return self.expected_output in self._format(stdout)

    def _format(self, string: str) -> str:
        return string.replace(" ", "").replace("\n", "")


def _get_dataset() -> Union[Dataset, DatasetDict]:
    try:
        return load_from_disk(str(DATASET_PATH))
    except FileNotFoundError:
        print("Dataset not found locally, downloading...")

    dataset = load_dataset("codeparrot/apps", trust_remote_code=True)
    dataset.save_to_disk(str(DATASET_PATH))

    return dataset


def load_apps(config: AppsConfig) -> Benchmark:
    """
    Loads the APPS benchmark, which consists of a series coding problems.

    Returns
    -------
    Benchmark
        A Benchmark object containing a list of Task objects for the APPS evaluation.
    """
    dataset = _get_dataset()
    tasks = []
    problems = list()
    for dataset_type in ["test", "train"]:
        problems += [
            Problem(
                id=problem["problem_id"],
                question=problem["question"],
                input_output=problem["input_output"],
                starter_code=problem["starter_code"],
            )
            for index, problem in enumerate(dataset[dataset_type])
            if (index < config.__getattribute__(dataset_type + "_end_index"))
            and (index >= config.__getattribute__(dataset_type + "_start_index"))
        ]

    for problem in problems:
        prompt = Prompt(
            problem.question
            + "\nThe program, including its inputs, should be run from the command "
            "line like 'python main \"input1 input2 etc \"', with all inputs inside "
            "the quotation marks. The program should not read inputs from stdin."
        )

        tasks.append(
            Task(
                name=str(problem.id),
                initial_code=FilesDict({"main.py": problem.starter_code}),
                command=None,  # Explicitly setting `None` because each assertion specifies its command
                prompt=prompt,
                assertions={
                    f"correct output {i}": AppsAssertion(
                        expected=problem.outputs[i],
                        command="python main.py" + ' "' + problem.inputs[i] + '"',
                    ).evaluate
                    for i in range(
                        min(len(problem.outputs), config.examples_per_problem)
                    )
                },
            )
        )

    return Benchmark(
        name="apps",
        tasks=tasks,
    )


================================================
FILE: gpt_engineer/benchmark/benchmarks/apps/problem.py
================================================
import json

from dataclasses import dataclass
from functools import cached_property
from typing import List


@dataclass(frozen=True)
class Problem:
    id: int
    question: str
    input_output: str
    starter_code: str

    @property
    def inputs(self) -> List[str]:
        return self._parsed_inputs_outputs["inputs"]

    @property
    def outputs(self) -> List[str]:
        return self._parsed_inputs_outputs["outputs"]

    @cached_property
    def _parsed_inputs_outputs(self):
        return json.loads(self.input_output.replace("\n", ""))


================================================
FILE: gpt_engineer/benchmark/benchmarks/apps/problems.py
================================================
# TODO: Pick problems
# Temporary testing against these problems
PROBLEM_IDS = list(range(0, 50))


================================================
FILE: gpt_engineer/benchmark/benchmarks/gptme/load.py
================================================
"""
Module for loading GPT-Me evaluation tasks.

This module provides functionality to load tasks for evaluating GPT-based models
on smaller, more focused tasks. It defines a set of tasks with predefined prompts
and assertions to benchmark the performance of AI models.

Functions
---------
load_gptme : function
    Loads the GPT-Me benchmark, which consists of a series of tasks for evaluation.
"""
from gpt_engineer.benchmark.bench_config import GptmeConfig
from gpt_engineer.benchmark.types import Benchmark, Task
from gpt_engineer.core.files_dict import FilesDict
from gpt_engineer.core.prompt import Prompt


def load_gptme(config: GptmeConfig) -> Benchmark:
    """
    Loads the GPT-Me benchmark, which consists of a series of tasks for evaluation.

    Returns
    -------
    Benchmark
        A Benchmark object containing a list of Task objects for the GPT-Me evaluation.
    """
    return Benchmark(
        name="gptme",
        tasks=[
            Task(
                name="hello",
                initial_code=FilesDict({"hello.py": "print('Hello, world!')"}),
                command="python hello.py",
                prompt=Prompt("Change the code in hello.py to print 'Hello, human!'"),
                assertions={
                    "correct output": lambda assertable: assertable.stdout
                    == "Hello, human!\n",
                    "correct file": lambda assertable: assertable.files[
                        "hello.py"
                    ].strip()
                    == "print('Hello, human!')",
                },
            ),
            Task(
                name="hello-patch",
                initial_code=FilesDict({"hello.py": "print('Hello, world!')"}),
                command="python hello.py",
                prompt=Prompt("Patch the code in hello.py to print 'Hello, human!'"),
                assertions={
                    "correct output": lambda assertable: assertable.stdout
                    == "Hello, human!\n",
                    "correct file": lambda assertable: assertable.files[
                        "hello.py"
                    ].strip()
                    == "print('Hello, human!')",
                },
            ),
            Task(
                name="hello-ask",
                initial_code=FilesDict({"hello.py": "print('Hello, world!')"}),
                command="echo 'Erik' | python hello.py",
                prompt=Prompt(
                    "modify hello.py to ask the user for their name and print 'Hello, <name>!'. don't try to execute it"
                ),
                assertions={
                    "correct output": lambda assertable: "Hello, Erik!"
                    in assertable.stdout,
                },
            ),
            Task(
                name="prime100",
                initial_code=FilesDict(
                    {}
                ),  # Empty dictionary since no initial code is provided
                command="python prime.py",
                prompt=Prompt(
                    "write a script prime.py that computes and prints the 100th prime number"
                ),
                assertions={
                    "correct output": lambda assertable: "541"
                    in assertable.stdout.split(),
                },
            ),
            Task(
                name="init-git",
                initial_code=FilesDict(
                    {}
                ),  # Empty dictionary since no initial code is provided
                command="git status",
                prompt=Prompt(
                    "initialize a git repository, write a main.py file, and commit it"
                ),
                assertions={
                    "clean exit": lambda assertable: assertable.process.returncode == 0,
                    "clean working tree": lambda assertable: "nothing to commit, working tree clean"
                    in assertable.stdout,
                    "main.py exists": lambda assertable: "main.py" in assertable.files,
                    "we have a commit": lambda assertable: "No commits yet"
                    not in assertable.stdout,
                },
            ),
        ],
    )


================================================
FILE: gpt_engineer/benchmark/benchmarks/load.py
================================================
"""
Module for loading benchmarks.

This module provides a central point to access different benchmarks by name.
It maps benchmark names to their respective loading functions.

Functions
---------
get_benchmark : function
    Retrieves a Benchmark object by name. Raises ValueError if the benchmark is unknown.
"""
from gpt_engineer.benchmark.bench_config import BenchConfig
from gpt_engineer.benchmark.benchmarks.apps.load import load_apps
from gpt_engineer.benchmark.benchmarks.gptme.load import load_gptme
from gpt_engineer.benchmark.benchmarks.mbpp.load import load_mbpp
from gpt_engineer.benchmark.types import Benchmark

BENCHMARKS = {
    "gptme": load_gptme,
    "apps": load_apps,
    "mbpp": load_mbpp,
}


def get_benchmark(name: str, config: BenchConfig) -> Benchmark:
    """
    Retrieves a Benchmark object by name. Raises ValueError if the benchmark is unknown.

    Parameters
    ----------
    name : str
        The name of the benchmark to retrieve.
    config : BenchConfig
        Configuration object for the benchmarks.

    Returns
    -------
    Benchmark
        The Benchmark object corresponding to the given name.

    Raises
    ------
    ValueError
        If the benchmark name is not found in the BENCHMARKS mapping.
    """
    if name not in BENCHMARKS:
        raise ValueError(f"Unknown benchmark {name}.")
    return BENCHMARKS[name](config.__getattribute__(name))


================================================
FILE: gpt_engineer/benchmark/benchmarks/mbpp/load.py
================================================
"""
Module for loading MBPP evaluation tasks.

This module provides functionality to load tasks for evaluating GPT-based models
on smaller, more focused tasks. It defines a set of tasks with predefined prompts
and assertions to benchmark the performance of AI models.

Functions
---------
load_mbpp : function
    Loads the MBPP benchmark, which consists of a series coding problems.
"""
from pathlib import Path
from subprocess import TimeoutExpired
from typing import Union

from datasets import Dataset, DatasetDict, load_dataset, load_from_disk

from gpt_engineer.benchmark.bench_config import MbppConfig
from gpt_engineer.benchmark.benchmarks.mbpp.problem import Problem
from gpt_engineer.benchmark.types import Assertable, Benchmark, Task
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv
from gpt_engineer.core.files_dict import FilesDict
from gpt_engineer.core.prompt import Prompt

DATASET_PATH = Path(__file__).parent / "dataset"


class MbppAssertion:
    def __init__(self, assertion: str):
        self.assertion = assertion

    def evaluate(self, assertable: Assertable) -> bool:
        generated_code = assertable.files["main.py"]
        code_with_assertion = f"{generated_code}\n{self.assertion}"

        # Create new execution environment for every run to avoid side effects
        env = DiskExecutionEnv()
        env.upload(FilesDict({"main.py": code_with_assertion}))
        pro = env.popen("python main.py")

        try:
            stdout, stderr = pro.communicate(timeout=2)
            stdout, stderr = stdout.decode("utf-8"), stderr.decode("utf-8")
        except TimeoutExpired:
            print("Execution Timeout")
            return False

        return not stderr


def _get_dataset() -> Union[Dataset, DatasetDict]:
    try:
        return load_from_disk(str(DATASET_PATH))
    except FileNotFoundError:
        print("Dataset not found locally, downloading...")

    dataset = load_dataset("mbpp", "sanitized", trust_remote_code=True)
    dataset.save_to_disk(str(DATASET_PATH))

    return dataset


def load_mbpp(config: MbppConfig) -> Benchmark:
    """
    Loads the MBPP benchmark, which consists of a series coding problems.

    Returns
    -------
    Benchmark
        A Benchmark object containing a list of Task objects for the MBPP evaluation.
    """
    dataset = _get_dataset()
    tasks = []
    problems = []
    for dataset_type in ["test", "train"]:
        problems += [
            Problem(
                source_file=problem["source_file"],
                task_id=problem["task_id"],
                prompt=problem["prompt"],
                code=problem["code"],
                test_imports=problem["test_imports"],
                test_list=problem["test_list"],
            )
            for index, problem in enumerate(dataset[dataset_type])
            if index < config.__getattribute__(dataset_type + "_len")
        ]

    for problem in problems:
        prompt = Prompt(
            problem.prompt
            + "Please extend given function without changing it's declaration including arguments."
        )

        tasks.append(
            Task(
                name=str(problem.task_id),
                initial_code=FilesDict({"main.py": problem.starting_code}),
                command=None,  # Explicitly setting `None` because each assertion runs code
                prompt=prompt,
                assertions={
                    f"correct assertion {i}": MbppAssertion(
                        assertion=assertion
                    ).evaluate
                    for i, assertion in enumerate(problem.test_list)
                },
            )
        )

    return Benchmark(
        name="mbpp",
        tasks=tasks,
    )


================================================
FILE: gpt_engineer/benchmark/benchmarks/mbpp/problem.py
================================================
from dataclasses import dataclass
from typing import List


@dataclass(frozen=True)
class Problem:
    source_file: int
    task_id: str
    prompt: str
    code: str
    test_imports: str
    test_list: List[str]

    @property
    def starting_code(self) -> str:
        lines: List[str] = []

        for line in self.code.split("\n"):
            lines.append(line)

            if line.startswith("def "):
                lines.append("pass #  TODO: Implement method\n")
                break

        return "\n".join(lines)


================================================
FILE: gpt_engineer/benchmark/benchmarks/mbpp/problems.py
================================================
# TODO: Pick problems
# Temporary testing against these problems
PROBLEM_IDS = range(0, 100)


================================================
FILE: gpt_engineer/benchmark/default_bench_config.toml
================================================
# For apps, the maximal range is 0:5000 for both train and test
[apps]
active = true
test_start_index = 0
test_end_index = 2
train_start_index = 0
train_end_index = 2

# For mbpp, the maximal range is 0:47
[mbpp]
active = true
test_len = 2
train_len = 2

[gptme]
active = true


================================================
FILE: gpt_engineer/benchmark/run.py
================================================
"""
Module for running benchmarks.

This module defines functions to run benchmarks using a given agent and to print
the results of the benchmark tasks.

Functions
---------
run : function
    Runs the benchmark tasks using the provided agent and returns a list of TaskResult objects.

print_results : function
    Prints the results of the benchmark tasks to the console.
"""
import time

from typing import List

import yaml

from gpt_engineer.benchmark.types import Assertable, Benchmark, TaskResult
from gpt_engineer.core.base_agent import BaseAgent
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv


def run(
    agent: BaseAgent,
    benchmark: Benchmark,
    verbose=False,
) -> List[TaskResult]:
    """
    Runs the benchmark tasks using the provided agent and returns a list of TaskResult objects.

    Parameters
    ----------
    agent : BaseAgent
        The agent to use for running the benchmark tasks.
    benchmark : Benchmark
        The benchmark containing the tasks to run.
    verbose : bool, default=False
        A flag to indicate whether to print verbose output during the benchmark.

    Returns
    -------
    List[TaskResult]
        A list of TaskResult objects representing the results of the benchmark tasks.
    """
    task_results = []
    for task in benchmark.tasks:
        print(f"--> Running task: {task.name}\n")

        t0 = time.time()
        files_dict = agent.improve(task.initial_code, task.prompt)
        t1 = time.time()

        env = DiskExecutionEnv()
        env.upload(files_dict)

        if task.command:
            p = env.popen(task.command)
            stdout, stderr = p.communicate(benchmark.timeout)
            stdout, stderr = stdout.decode("utf-8"), stderr.decode("utf-8")
        else:
            p, stdout, stderr = None, None, None

        exec_result = Assertable(
            files=files_dict,
            env=env,
            process=p,
            stdout=stdout,
            stderr=stderr,
        )

        task_results.append(
            TaskResult(
                task_name=task.name,
                assertion_results={
                    assertion_name: assertion(exec_result)
                    for assertion_name, assertion in task.assertions.items()
                },
                duration=t1 - t0,
            )
        )

        if verbose:
            print_results(task_results)
    return task_results


def print_results(results: list[TaskResult]):
    """
    Prints the results of the benchmark tasks to the console.

    Parameters
    ----------
    results : list[TaskResult]
        A list of TaskResult objects representing the results of the benchmark tasks.

    Returns
    -------
    None
    """
    for task_result in results:
        print(f"\n--- Results for {task_result.task_name} ---")
        print(f"{task_result.task_name} ({task_result.duration:.2f}s)")
        for assertion_name, assertion_result in task_result.assertion_results.items():
            checkmark = "✅" if assertion_result else "❌"
            print(f"  {checkmark} {assertion_name}")
        print()

    success_rates = [task_result.success_rate for task_result in results]
    avg_success_rate = sum(success_rates) / len(results)

    total_time = sum(task_result.duration for task_result in results)

    correct_assertions = sum(
        sum(
            assertion_result
            for assertion_result in task_result.assertion_results.values()
        )
        for task_result in results
    )
    total_assertions = sum(
        len(task_result.assertion_results) for task_result in results
    )
    correct_tasks = [
        task_result for task_result in results if task_result.success_rate == 1
    ]

    print("--- Results ---")
    print(f"Total time: {total_time:.2f}s")
    print(f"Completely correct tasks: {len(correct_tasks)}/{len(results)}")
    print(f"Total correct assertions: {correct_assertions}/{total_assertions}")
    print(f"Average success rate: {avg_success_rate * 100}% on {len(results)} tasks")
    print("--- Results ---")
    print()


def export_yaml_results(yaml_path, complete_results, config):
    for results in complete_results.values():
        correct_tasks = [
            task_result
            for task_result in results["detailed"]
            if task_result["solved"] == 1.0
        ]
        fraction_correct = len(correct_tasks) / len(results["detailed"])
        results["fully_solved"] = fraction_correct
    complete_results["config"] = config
    with open(yaml_path, "w") as f:
        yaml.dump(complete_results, f, indent=4)


================================================
FILE: gpt_engineer/benchmark/types.py
================================================
"""
Module defining types used in benchmarking.

This module contains dataclass definitions for various types used throughout the
benchmarking process, such as Assertable, Task, Benchmark, and TaskResult.

Classes:
    Assertable:
        Represents an object that can be asserted against in a benchmark task.

    Assertion:
        Type alias for a callable that takes an Assertable and returns a boolean.

    Task:
        Represents a single task within a benchmark, including its assertions.

    Benchmark:
        Represents a collection of tasks used to evaluate a model's performance.

    TaskResult:
        Represents the result of running a single task within a benchmark.
"""
from dataclasses import dataclass
from subprocess import Popen
from typing import Callable, Dict, Optional

from gpt_engineer.core.base_execution_env import BaseExecutionEnv
from gpt_engineer.core.files_dict import FilesDict
from gpt_engineer.core.prompt import Prompt


@dataclass
class Assertable:
    """
    A class representing an object which can be asserted against.

    Attributes:
        files (FilesDict): The code files involved in the assertion.
        env (BaseExecutionEnv): The execution environment in which the code is run.
        process (Popen): The subprocess in which the code is run.
        stdout (str): The standard output from the code execution.
        stderr (str): The standard error from the code execution.
    """

    files: FilesDict
    env: BaseExecutionEnv
    process: Optional[Popen]
    stdout: Optional[str]
    stderr: Optional[str]


Assertion = Callable[[Assertable], bool]


@dataclass
class Task:
    name: str
    initial_code: Optional[FilesDict]
    command: Optional[str]
    prompt: Prompt
    assertions: Optional[Dict[str, Assertion]]


@dataclass
class Benchmark:
    """A benchmark is a collection of tasks that evaluate a model's performance."""

    name: str
    tasks: list[Task]
    timeout: Optional[int] = None


@dataclass
class TaskResult:
    task_name: str
    assertion_results: dict[str, bool]
    duration: float

    # Returns success rate from 0.00 up to 1.00
    @property
    def success_rate(self) -> float:
        if not self.assertion_results:
            return 0.0

        succeeded = len(
            [result for result in self.assertion_results.values() if result is True]
        )

        return succeeded / len(self.assertion_results)

    def to_dict(self) -> dict:
        out_dict = {key: value for key, value in self.__dict__.items()}
        out_dict["solved"] = self.success_rate
        return out_dict


================================================
FILE: gpt_engineer/core/__init__.py
================================================


================================================
FILE: gpt_engineer/core/ai.py
================================================
"""
AI Module

This module provides an AI class that interfaces with language models to perform various tasks such as
starting a conversation, advancing the conversation, and handling message serialization. It also includes
backoff strategies for handling rate limit errors from the OpenAI API.

Classes:
    AI: A class that interfaces with language models for conversation management and message serialization.

Functions:
    serialize_messages(messages: List[Message]) -> str
        Serialize a list of messages to a JSON string.
"""

from __future__ import annotations

import json
import logging
import os

from pathlib import Path
from typing import Any, List, Optional, Union

import backoff
import openai
import pyperclip

from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.chat_models.base import BaseChatModel
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage,
    messages_from_dict,
    messages_to_dict,
)
from langchain_anthropic import ChatAnthropic
from langchain_openai import AzureChatOpenAI, ChatOpenAI

from gpt_engineer.core.token_usage import TokenUsageLog

# Type hint for a chat message
Message = Union[AIMessage, HumanMessage, SystemMessage]

# Set up logging
logger = logging.getLogger(__name__)


class AI:
    """
    A class that interfaces with language models for conversation management and message serialization.

    This class provides methods to start and advance conversations, handle message serialization,
    and implement backoff strategies for rate limit errors when interacting with the OpenAI API.

    Attributes
    ----------
    temperature : float
        The temperature setting for the language model.
    azure_endpoint : str
        The endpoint URL for the Azure-hosted language model.
    model_name : str
        The name of the language model to use.
    streaming : bool
        A flag indicating whether to use streaming for the language model.
    llm : BaseChatModel
        The language model instance for conversation management.
    token_usage_log : TokenUsageLog
        A log for tracking token usage during conversations.

    Methods
    -------
    start(system: str, user: str, step_name: str) -> List[Message]
        Start the conversation with a system message and a user message.
    next(messages: List[Message], prompt: Optional[str], step_name: str) -> List[Message]
        Advances the conversation by sending message history to LLM and updating with the response.
    backoff_inference(messages: List[Message]) -> Any
        Perform inference using the language model with an exponential backoff strategy.
    serialize_messages(messages: List[Message]) -> str
        Serialize a list of messages to a JSON string.
    deserialize_messages(jsondictstr: str) -> List[Message]
        Deserialize a JSON string to a list of messages.
    _create_chat_model() -> BaseChatModel
        Create a chat model with the specified model name and temperature.
    """

    def __init__(
        self,
        model_name="gpt-4-turbo",
        temperature=0.1,
        azure_endpoint=None,
        streaming=True,
        vision=False,
    ):
        """
        Initialize the AI class.

        Parameters
        ----------
        model_name : str, optional
            The name of the model to use, by default "gpt-4".
        temperature : float, optional
            The temperature to use for the model, by default 0.1.
        """
        self.temperature = temperature
        self.azure_endpoint = azure_endpoint
        self.model_name = model_name
        self.streaming = streaming
        self.vision = (
            ("vision-preview" in model_name)
            or ("gpt-4-turbo" in model_name and "preview" not in model_name)
            or ("claude" in model_name)
        )
        self.llm = self._create_chat_model()
        self.token_usage_log = TokenUsageLog(model_name)

        logger.debug(f"Using model {self.model_name}")

    def start(self, system: str, user: Any, *, step_name: str) -> List[Message]:
        """
        Start the conversation with a system message and a user message.

        Parameters
        ----------
        system : str
            The content of the system message.
        user : str
            The content of the user message.
        step_name : str
            The name of the step.

        Returns
        -------
        List[Message]
            The list of messages in the conversation.
        """

        messages: List[Message] = [
            SystemMessage(content=system),
            HumanMessage(content=user),
        ]
        return self.next(messages, step_name=step_name)

    def _extract_content(self, content):
        """
        Extracts text content from a message, supporting both string and list types.
        Parameters
        ----------
        content : Union[str, List[dict]]
            The content of a message, which could be a string or a list.
        Returns
        -------
        str
            The extracted text content.
        """
        if isinstance(content, str):
            return content
        elif isinstance(content, list) and content and "text" in content[0]:
            # Assuming the structure of list content is [{'type': 'text', 'text': 'Some text'}, ...]
            return content[0]["text"]
        else:
            return ""

    def _collapse_text_messages(self, messages: List[Message]):
        """
        Combine consecutive messages of the same type into a single message, where if the message content
        is a list type, the first text element's content is taken. This method keeps `combined_content` as a string.

        This method iterates through the list of messages, combining consecutive messages of the same type
        by joining their content with a newline character. If the content is a list, it extracts text from the first
        text element's content. This reduces the number of messages and simplifies the conversation for processing.

        Parameters
        ----------
        messages : List[Message]
            The list of messages to collapse.

        Returns
        -------
        List[Message]
            The list of messages after collapsing consecutive messages of the same type.
        """
        collapsed_messages = []
        if not messages:
            return collapsed_messages

        previous_message = messages[0]
        combined_content = self._extract_content(previous_message.content)

        for current_message in messages[1:]:
            if current_message.type == previous_message.type:
                combined_content += "\n\n" + self._extract_content(
                    current_message.content
                )
            else:
                collapsed_messages.append(
                    previous_message.__class__(content=combined_content)
                )
                previous_message = current_message
                combined_content = self._extract_content(current_message.content)

        collapsed_messages.append(previous_message.__class__(content=combined_content))
        return collapsed_messages

    def next(
        self,
        messages: List[Message],
        prompt: Optional[str] = None,
        *,
        step_name: str,
    ) -> List[Message]:
        """
        Advances the conversation by sending message history
        to LLM and updating with the response.

        Parameters
        ----------
        messages : List[Message]
            The list of messages in the conversation.
        prompt : Optional[str], optional
            The prompt to use, by default None.
        step_name : str
            The name of the step.

        Returns
        -------
        List[Message]
            The updated list of messages in the conversation.
        """

        if prompt:
            messages.append(HumanMessage(content=prompt))

        logger.debug(
            "Creating a new chat completion: %s",
            "\n".join([m.pretty_repr() for m in messages]),
        )

        if not self.vision:
            messages = self._collapse_text_messages(messages)

        response = self.backoff_inference(messages)

        self.token_usage_log.update_log(
            messages=messages, answer=response.content, step_name=step_name
        )
        messages.append(response)
        logger.debug(f"Chat completion finished: {messages}")

        return messages

    @backoff.on_exception(backoff.expo, openai.RateLimitError, max_tries=7, max_time=45)
    def backoff_inference(self, messages):
        """
        Perform inference using the language model while implementing an exponential backoff strategy.

        This function will retry the inference in case of a rate limit error from the OpenAI API.
        It uses an exponential backoff strategy, meaning the wait time between retries increases
        exponentially. The function will attempt to retry up to 7 times within a span of 45 seconds.

        Parameters
        ----------
        messages : List[Message]
            A list of chat messages which will be passed to the language model for processing.

        callbacks : List[Callable]
            A list of callback functions that are triggered after each inference. These functions
            can be used for logging, monitoring, or other auxiliary tasks.

        Returns
        -------
        Any
            The output from the language model after processing the provided messages.

        Raises
        ------
        openai.error.RateLimitError
            If the number of retries exceeds the maximum or if the rate limit persists beyond the
            allotted time, the function will ultimately raise a RateLimitError.

        Example
        -------
        >>> messages = [SystemMessage(content="Hello"), HumanMessage(content="How's the weather?")]
        >>> response = backoff_inference(messages)
        """
        return self.llm.invoke(messages)  # type: ignore

    @staticmethod
    def serialize_messages(messages: List[Message]) -> str:
        """
        Serialize a list of messages to a JSON string.

        Parameters
        ----------
        messages : List[Message]
            The list of messages to serialize.

        Returns
        -------
        str
            The serialized messages as a JSON string.
        """
        return json.dumps(messages_to_dict(messages))

    @staticmethod
    def deserialize_messages(jsondictstr: str) -> List[Message]:
        """
        Deserialize a JSON string to a list of messages.

        Parameters
        ----------
        jsondictstr : str
            The JSON string to deserialize.

        Returns
        -------
        List[Message]
            The deserialized list of messages.
        """
        data = json.loads(jsondictstr)
        # Modify implicit is_chunk property to ALWAYS false
        # since Langchain's Message schema is stricter
        prevalidated_data = [
            {**item, "tools": {**item.get("tools", {}), "is_chunk": False}}
            for item in data
        ]
        return list(messages_from_dict(prevalidated_data))  # type: ignore

    def _create_chat_model(self) -> BaseChatModel:
        """
        Create a chat model with the specified model name and temperature.

        Parameters
        ----------
        model : str
            The name of the model to create.
        temperature : float
            The temperature to use for the model.

        Returns
        -------
        BaseChatModel
            The created chat model.
        """
        if self.azure_endpoint:
            return AzureChatOpenAI(
                azure_endpoint=self.azure_endpoint,
                openai_api_version=os.getenv(
                    "OPENAI_API_VERSION", "2024-05-01-preview"
                ),
                deployment_name=self.model_name,
                openai_api_type="azure",
                streaming=self.streaming,
                callbacks=[StreamingStdOutCallbackHandler()],
            )
        elif "claude" in self.model_name:
            return ChatAnthropic(
                model=self.model_name,
                temperature=self.temperature,
                callbacks=[StreamingStdOutCallbackHandler()],
                streaming=self.streaming,
                max_tokens_to_sample=4096,
            )
        elif self.vision:
            return ChatOpenAI(
                model=self.model_name,
                temperature=self.temperature,
                streaming=self.streaming,
                callbacks=[StreamingStdOutCallbackHandler()],
                max_tokens=4096,  # vision models default to low max token limits
            )
        else:
            return ChatOpenAI(
                model=self.model_name,
                temperature=self.temperature,
                streaming=self.streaming,
                callbacks=[StreamingStdOutCallbackHandler()],
            )


def serialize_messages(messages: List[Message]) -> str:
    return AI.serialize_messages(messages)


class ClipboardAI(AI):
    # Ignore not init superclass
    def __init__(self, **_):  # type: ignore
        self.vision = False
        self.token_usage_log = TokenUsageLog("clipboard_llm")

    @staticmethod
    def serialize_messages(messages: List[Message]) -> str:
        return "\n\n".join([f"{m.type}:\n{m.content}" for m in messages])

    @staticmethod
    def multiline_input():
        print("Enter/Paste your content. Ctrl-D or Ctrl-Z ( windows ) to save it.")
        content = []
        while True:
            try:
                line = input()
            except EOFError:
                break
            content.append(line)
        return "\n".join(content)

    def next(
        self,
        messages: List[Message],
        prompt: Optional[str] = None,
        *,
        step_name: str,
    ) -> List[Message]:
        """
        Not yet fully supported
        """
        if prompt:
            messages.append(HumanMessage(content=prompt))

        logger.debug(f"Creating a new chat completion: {messages}")

        msgs = self.serialize_messages(messages)
        pyperclip.copy(msgs)
        Path("clipboard.txt").write_text(msgs)
        print(
            "Messages copied to clipboard and written to clipboard.txt,",
            len(msgs),
            "characters in total",
        )

        response = self.multiline_input()

        messages.append(AIMessage(content=response))
       
Download .txt
gitextract_dhh25wks/

├── .dockerignore
├── .github/
│   ├── CODEOWNERS
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   ├── documentation-clarification.md
│   │   └── feature-request.md
│   ├── PULL_REQUEST_TEMPLATE/
│   │   └── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── automation.yml
│       ├── ci.yaml
│       ├── pre-commit.yaml
│       └── release.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── Acknowledgements.md
├── DISCLAIMER.md
├── GOVERNANCE.md
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── ROADMAP.md
├── TERMS_OF_USE.md
├── WINDOWS_README.md
├── citation.cff
├── docker/
│   ├── Dockerfile
│   ├── README.md
│   └── entrypoint.sh
├── docker-compose.yml
├── docs/
│   ├── Makefile
│   ├── api_reference.rst
│   ├── code_conduct_link.rst
│   ├── conf.py
│   ├── contributing_link.rst
│   ├── create_api_rst.py
│   ├── disclaimer_link.rst
│   ├── docs_building.md
│   ├── examples/
│   │   └── open_llms/
│   │       ├── README.md
│   │       ├── langchain_interface.py
│   │       └── openai_api_interface.py
│   ├── index.rst
│   ├── installation.rst
│   ├── introduction.md
│   ├── make.bat
│   ├── open_models.md
│   ├── quickstart.rst
│   ├── roadmap_link.rst
│   ├── terms_link.rst
│   ├── tracing_debugging.md
│   └── windows_readme_link.rst
├── gpt_engineer/
│   ├── __init__.py
│   ├── applications/
│   │   ├── __init__.py
│   │   └── cli/
│   │       ├── __init__.py
│   │       ├── cli_agent.py
│   │       ├── collect.py
│   │       ├── file_selector.py
│   │       ├── learning.py
│   │       └── main.py
│   ├── benchmark/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── bench_config.py
│   │   ├── benchmarks/
│   │   │   ├── apps/
│   │   │   │   ├── load.py
│   │   │   │   ├── problem.py
│   │   │   │   └── problems.py
│   │   │   ├── gptme/
│   │   │   │   └── load.py
│   │   │   ├── load.py
│   │   │   └── mbpp/
│   │   │       ├── load.py
│   │   │       ├── problem.py
│   │   │       └── problems.py
│   │   ├── default_bench_config.toml
│   │   ├── run.py
│   │   └── types.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── ai.py
│   │   ├── base_agent.py
│   │   ├── base_execution_env.py
│   │   ├── base_memory.py
│   │   ├── chat_to_files.py
│   │   ├── default/
│   │   │   ├── __init__.py
│   │   │   ├── constants.py
│   │   │   ├── disk_execution_env.py
│   │   │   ├── disk_memory.py
│   │   │   ├── file_store.py
│   │   │   ├── paths.py
│   │   │   ├── simple_agent.py
│   │   │   └── steps.py
│   │   ├── diff.py
│   │   ├── files_dict.py
│   │   ├── git.py
│   │   ├── linting.py
│   │   ├── preprompts_holder.py
│   │   ├── project_config.py
│   │   ├── prompt.py
│   │   ├── token_usage.py
│   │   └── version_manager.py
│   ├── preprompts/
│   │   ├── clarify
│   │   ├── entrypoint
│   │   ├── file_format
│   │   ├── file_format_diff
│   │   ├── file_format_fix
│   │   ├── generate
│   │   ├── improve
│   │   ├── philosophy
│   │   └── roadmap
│   └── tools/
│       ├── __init__.py
│       ├── custom_steps.py
│       └── supported_languages.py
├── projects/
│   ├── example-improve/
│   │   ├── README.md
│   │   ├── controller.py
│   │   ├── main.py
│   │   ├── model.py
│   │   ├── prompt
│   │   ├── requirements.txt
│   │   ├── run.sh
│   │   └── view.py
│   └── example-vision/
│       ├── navigation.html
│       └── prompt
├── pyproject.toml
├── scripts/
│   ├── clean_benchmarks.py
│   ├── legacy_benchmark.py
│   ├── print_chat.py
│   └── test_api.py
├── sweep.yaml
├── tests/
│   ├── __init__.py
│   ├── ai_cache.json
│   ├── applications/
│   │   ├── __init__.py
│   │   └── cli/
│   │       ├── __init__.py
│   │       ├── test_cli_agent.py
│   │       ├── test_collect.py
│   │       ├── test_collection_consent.py
│   │       ├── test_learning.py
│   │       └── test_main.py
│   ├── benchmark/
│   │   └── test_BenchConfig.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── default/
│   │   │   ├── __init__.py
│   │   │   ├── test_disk_execution_env.py
│   │   │   ├── test_disk_file_repository.py
│   │   │   ├── test_simple_agent.py
│   │   │   └── test_steps.py
│   │   ├── improve_function_test_cases/
│   │   │   ├── apps_benchmark_6_chat
│   │   │   ├── apps_benchmark_6_code
│   │   │   ├── apps_benchmark_6_v2_chat
│   │   │   ├── apps_benchmark_6_v2_code
│   │   │   ├── controller_chat
│   │   │   ├── controller_code
│   │   │   ├── corrected_diff_from_missing_lines
│   │   │   ├── create_two_new_files_chat
│   │   │   ├── create_two_new_files_code
│   │   │   ├── simple_calculator_chat
│   │   │   ├── simple_calculator_code
│   │   │   ├── task_master_chat
│   │   │   ├── task_master_code
│   │   │   ├── temperature_converter_chat
│   │   │   ├── temperature_converter_code
│   │   │   ├── theo_case_chat
│   │   │   ├── theo_case_code
│   │   │   ├── vgvishesh_example_2_chat
│   │   │   ├── vgvishesh_example_2_code
│   │   │   ├── vgvishesh_example_chat
│   │   │   ├── vgvishesh_example_code
│   │   │   ├── wheaties_example_chat
│   │   │   ├── wheaties_example_code
│   │   │   ├── zbf_yml_missing_chat
│   │   │   └── zbf_yml_missing_code
│   │   ├── test_ai.py
│   │   ├── test_chat_to_files.py
│   │   ├── test_file_selector_enhancements.py
│   │   ├── test_git.py
│   │   ├── test_salvage_correct_hunks.py
│   │   └── test_token_usage.py
│   ├── mock_ai.py
│   ├── test_install.py
│   ├── test_project_config.py
│   └── tools/
│       └── example_snake_files.py
└── tox.ini
Download .txt
SYMBOL INDEX (417 symbols across 62 files)

FILE: docs/create_api_rst.py
  function load_members (line 13) | def load_members() -> dict:
  function construct_doc (line 31) | def construct_doc(members: dict) -> str:
  function main (line 90) | def main() -> None:

FILE: gpt_engineer/applications/cli/cli_agent.py
  class CliAgent (line 36) | class CliAgent(BaseAgent):
    method __init__ (line 84) | def __init__(
    method with_default_config (line 103) | def with_default_config(
    method init (line 152) | def init(self, prompt: Prompt) -> FilesDict:
    method improve (line 185) | def improve(

FILE: gpt_engineer/applications/cli/collect.py
  function send_learning (line 37) | def send_learning(learning: Learning):
  function collect_learnings (line 65) | def collect_learnings(
  function collect_and_send_human_review (line 141) | def collect_and_send_human_review(

FILE: gpt_engineer/applications/cli/file_selector.py
  class FileSelector (line 35) | class FileSelector:
    method __init__ (line 66) | def __init__(self, project_path: Union[str, Path]):
    method ask_for_files (line 79) | def ask_for_files(self, skip_file_selection=False) -> tuple[FilesDict,...
    method editor_file_selector (line 123) | def editor_file_selector(
    method open_with_default_editor (line 212) | def open_with_default_editor(self, file_path: Union[str, Path]):
    method is_utf8 (line 249) | def is_utf8(self, file_path: Union[str, Path]) -> bool:
    method get_files_from_toml (line 271) | def get_files_from_toml(
    method merge_file_lists (line 344) | def merge_file_lists(
    method should_filter_file (line 370) | def should_filter_file(self, file_path: Path, filters: List[str]) -> b...
    method get_current_files (line 379) | def get_current_files(self, project_path: Union[str, Path]) -> List[str]:
  class DisplayablePath (line 419) | class DisplayablePath(object):
    method __init__ (line 432) | def __init__(
    method display_name (line 455) | def display_name(self) -> str:
    method make_tree (line 464) | def make_tree(
    method _default_criteria (line 505) | def _default_criteria(cls, path: Path) -> bool:
    method displayable (line 511) | def displayable(self) -> str:

FILE: gpt_engineer/applications/cli/learning.py
  class Review (line 48) | class Review:
  class Learning (line 75) | class Learning:
  function human_review_input (line 122) | def human_review_input() -> Optional[Review]:
  function ask_for_valid_input (line 177) | def ask_for_valid_input(ran):
  function check_collection_consent (line 183) | def check_collection_consent() -> bool:
  function ask_collection_consent (line 201) | def ask_collection_consent() -> bool:
  function extract_learning (line 237) | def extract_learning(
  function get_session (line 279) | def get_session() -> str:

FILE: gpt_engineer/applications/cli/main.py
  function load_env_if_needed (line 71) | def load_env_if_needed():
  function concatenate_paths (line 93) | def concatenate_paths(base_path, sub_path):
  function load_prompt (line 105) | def load_prompt(
  function get_preprompts_path (line 173) | def get_preprompts_path(use_custom_preprompts: bool, input_path: Path) -...
  function compare (line 203) | def compare(f1: FilesDict, f2: FilesDict):
  function prompt_yesno (line 232) | def prompt_yesno() -> bool:
  function get_system_info (line 243) | def get_system_info():
  function get_installed_packages (line 254) | def get_installed_packages():
  function format_installed_packages (line 267) | def format_installed_packages(packages):
  function main (line 281) | def main(

FILE: gpt_engineer/benchmark/__main__.py
  function get_agent (line 43) | def get_agent(path):
  function main (line 71) | def main(

FILE: gpt_engineer/benchmark/bench_config.py
  class AppsConfig (line 10) | class AppsConfig:
  class MbppConfig (line 20) | class MbppConfig:
  class GptmeConfig (line 27) | class GptmeConfig:
  class BenchConfig (line 32) | class BenchConfig:
    method from_toml (line 40) | def from_toml(cls, config_file: Path | str):
    method from_dict (line 47) | def from_dict(cls, config_dict: dict):
    method recursive_resolve (line 55) | def recursive_resolve(data_dict):
    method to_dict (line 62) | def to_dict(self):

FILE: gpt_engineer/benchmark/benchmarks/apps/load.py
  class AppsAssertion (line 29) | class AppsAssertion:
    method __init__ (line 30) | def __init__(self, expected: str, command: str):
    method evaluate (line 34) | def evaluate(self, assertable: Assertable) -> bool:
    method _format (line 48) | def _format(self, string: str) -> str:
  function _get_dataset (line 52) | def _get_dataset() -> Union[Dataset, DatasetDict]:
  function load_apps (line 64) | def load_apps(config: AppsConfig) -> Benchmark:

FILE: gpt_engineer/benchmark/benchmarks/apps/problem.py
  class Problem (line 9) | class Problem:
    method inputs (line 16) | def inputs(self) -> List[str]:
    method outputs (line 20) | def outputs(self) -> List[str]:
    method _parsed_inputs_outputs (line 24) | def _parsed_inputs_outputs(self):

FILE: gpt_engineer/benchmark/benchmarks/gptme/load.py
  function load_gptme (line 19) | def load_gptme(config: GptmeConfig) -> Benchmark:

FILE: gpt_engineer/benchmark/benchmarks/load.py
  function get_benchmark (line 25) | def get_benchmark(name: str, config: BenchConfig) -> Benchmark:

FILE: gpt_engineer/benchmark/benchmarks/mbpp/load.py
  class MbppAssertion (line 29) | class MbppAssertion:
    method __init__ (line 30) | def __init__(self, assertion: str):
    method evaluate (line 33) | def evaluate(self, assertable: Assertable) -> bool:
  function _get_dataset (line 52) | def _get_dataset() -> Union[Dataset, DatasetDict]:
  function load_mbpp (line 64) | def load_mbpp(config: MbppConfig) -> Benchmark:

FILE: gpt_engineer/benchmark/benchmarks/mbpp/problem.py
  class Problem (line 6) | class Problem:
    method starting_code (line 15) | def starting_code(self) -> str:

FILE: gpt_engineer/benchmark/run.py
  function run (line 26) | def run(
  function print_results (line 90) | def print_results(results: list[TaskResult]):
  function export_yaml_results (line 139) | def export_yaml_results(yaml_path, complete_results, config):

FILE: gpt_engineer/benchmark/types.py
  class Assertable (line 33) | class Assertable:
  class Task (line 56) | class Task:
  class Benchmark (line 65) | class Benchmark:
  class TaskResult (line 74) | class TaskResult:
    method success_rate (line 81) | def success_rate(self) -> float:
    method to_dict (line 91) | def to_dict(self) -> dict:

FILE: gpt_engineer/core/ai.py
  class AI (line 50) | class AI:
    method __init__ (line 88) | def __init__(
    method start (line 120) | def start(self, system: str, user: Any, *, step_name: str) -> List[Mes...
    method _extract_content (line 145) | def _extract_content(self, content):
    method _collapse_text_messages (line 165) | def _collapse_text_messages(self, messages: List[Message]):
    method next (line 206) | def next(
    method backoff_inference (line 254) | def backoff_inference(self, messages):
    method serialize_messages (line 290) | def serialize_messages(messages: List[Message]) -> str:
    method deserialize_messages (line 307) | def deserialize_messages(jsondictstr: str) -> List[Message]:
    method _create_chat_model (line 330) | def _create_chat_model(self) -> BaseChatModel:
  function serialize_messages (line 382) | def serialize_messages(messages: List[Message]) -> str:
  class ClipboardAI (line 386) | class ClipboardAI(AI):
    method __init__ (line 388) | def __init__(self, **_):  # type: ignore
    method serialize_messages (line 393) | def serialize_messages(messages: List[Message]) -> str:
    method multiline_input (line 397) | def multiline_input():
    method next (line 408) | def next(

FILE: gpt_engineer/core/base_agent.py
  class BaseAgent (line 17) | class BaseAgent(ABC):
    method init (line 26) | def init(self, prompt: Prompt) -> FilesDict:
    method improve (line 30) | def improve(self, files_dict: FilesDict, prompt: Prompt) -> FilesDict:

FILE: gpt_engineer/core/base_execution_env.py
  class BaseExecutionEnv (line 8) | class BaseExecutionEnv(ABC):
    method run (line 17) | def run(self, command: str, timeout: Optional[int] = None) -> Tuple[st...
    method popen (line 24) | def popen(self, command: str) -> Popen:
    method upload (line 31) | def upload(self, files: FilesDict) -> "BaseExecutionEnv":
    method download (line 38) | def download(self) -> FilesDict:

FILE: gpt_engineer/core/chat_to_files.py
  function chat_to_files_dict (line 38) | def chat_to_files_dict(chat: str) -> FilesDict:
  function apply_diffs (line 69) | def apply_diffs(diffs: Dict[str, Diff], files: FilesDict) -> FilesDict:
  function parse_diffs (line 123) | def parse_diffs(diff_string: str, diff_timeout=3) -> dict:
  function parse_diff_block (line 164) | def parse_diff_block(diff_block: str) -> dict:
  function parse_hunk_header (line 221) | def parse_hunk_header(header_line) -> Tuple[int, int, int, int]:

FILE: gpt_engineer/core/default/disk_execution_env.py
  class DiskExecutionEnv (line 36) | class DiskExecutionEnv(BaseExecutionEnv):
    method __init__ (line 52) | def __init__(self, path: Union[str, Path, None] = None):
    method upload (line 55) | def upload(self, files: FilesDict) -> "DiskExecutionEnv":
    method download (line 59) | def download(self) -> FilesDict:
    method popen (line 62) | def popen(self, command: str) -> subprocess.Popen:
    method run (line 72) | def run(self, command: str, timeout: Optional[int] = None) -> Tuple[st...

FILE: gpt_engineer/core/default/disk_memory.py
  class DiskMemory (line 36) | class DiskMemory(BaseMemory):
    method __init__ (line 50) | def __init__(self, path: Union[str, Path]):
    method __contains__ (line 64) | def __contains__(self, key: str) -> bool:
    method __getitem__ (line 81) | def __getitem__(self, key: str) -> str:
    method get (line 116) | def get(self, key: str, default: Optional[Any] = None) -> Any:
    method __setitem__ (line 144) | def __setitem__(self, key: Union[str, Path], val: str) -> None:
    method __delitem__ (line 174) | def __delitem__(self, key: Union[str, Path]) -> None:
    method __iter__ (line 198) | def __iter__(self) -> Iterator[str]:
    method __len__ (line 216) | def __len__(self) -> int:
    method _supported_files (line 228) | def _supported_files(self) -> str:
    method _all_files (line 239) | def _all_files(self) -> str:
    method to_path_list_string (line 243) | def to_path_list_string(self, supported_code_files_only: bool = False)...
    method to_dict (line 264) | def to_dict(self) -> Dict[Union[str, Path], str]:
    method to_json (line 276) | def to_json(self) -> str:
    method log (line 288) | def log(self, key: Union[str, Path], val: str) -> None:
    method archive_logs (line 318) | def archive_logs(self):

FILE: gpt_engineer/core/default/file_store.py
  class FileStore (line 10) | class FileStore:
    method __init__ (line 31) | def __init__(self, path: Union[str, Path, None] = None):
    method push (line 39) | def push(self, files: FilesDict):
    method linting (line 47) | def linting(self, files: FilesDict) -> FilesDict:
    method pull (line 52) | def pull(self) -> FilesDict:

FILE: gpt_engineer/core/default/paths.py
  function memory_path (line 55) | def memory_path(path):
  function metadata_path (line 72) | def metadata_path(path):

FILE: gpt_engineer/core/default/simple_agent.py
  class SimpleAgent (line 27) | class SimpleAgent(BaseAgent):
    method __init__ (line 47) | def __init__(
    method with_default_config (line 60) | def with_default_config(
    method init (line 70) | def init(self, prompt: Prompt) -> FilesDict:
    method improve (line 79) | def improve(
  function default_config_agent (line 91) | def default_config_agent():

FILE: gpt_engineer/core/default/steps.py
  function curr_fn (line 63) | def curr_fn() -> str:
  function setup_sys_prompt (line 75) | def setup_sys_prompt(preprompts: MutableMapping[Union[str, Path], str]) ...
  function setup_sys_prompt_existing_code (line 97) | def setup_sys_prompt_existing_code(
  function gen_code (line 121) | def gen_code(
  function gen_entrypoint (line 153) | def gen_entrypoint(
  function execute_entrypoint (line 205) | def execute_entrypoint(
  function improve_fn (line 271) | def improve_fn(
  function _improve_loop (line 315) | def _improve_loop(
  function salvage_correct_hunks (line 341) | def salvage_correct_hunks(
  class Tee (line 363) | class Tee(object):
    method __init__ (line 364) | def __init__(self, *files):
    method write (line 367) | def write(self, obj):
    method flush (line 371) | def flush(self):
  function handle_improve_mode (line 376) | def handle_improve_mode(prompt, agent, memory, files_dict, diff_timeout=3):

FILE: gpt_engineer/core/diff.py
  class Hunk (line 44) | class Hunk:
    method __init__ (line 58) | def __init__(
    method add_retained_line (line 80) | def add_retained_line(self, line, index) -> None:
    method relabel_line (line 85) | def relabel_line(self, index, new_label) -> None:
    method pop_line (line 92) | def pop_line(self, line, index) -> None:
    method add_lines (line 98) | def add_lines(self, new_lines) -> None:
    method hunk_to_string (line 104) | def hunk_to_string(self) -> str:
    method make_forward_block (line 114) | def make_forward_block(self, hunk_ind: int, forward_block_len) -> str:
    method check_start_line (line 122) | def check_start_line(self, lines_dict: dict) -> bool:
    method find_start_line (line 133) | def find_start_line(self, lines_dict: dict, problems: list) -> bool:
    method validate_lines (line 200) | def validate_lines(self, lines_dict: dict, problems: list) -> bool:
    method validate_and_correct (line 288) | def validate_and_correct(
  class Diff (line 312) | class Diff:
    method __init__ (line 322) | def __init__(self, filename_pre, filename_post) -> None:
    method is_new_file (line 327) | def is_new_file(self) -> bool:
    method diff_to_string (line 333) | def diff_to_string(self) -> str:
    method validate_and_correct (line 340) | def validate_and_correct(self, lines_dict: dict) -> List[str]:
  function is_similar (line 381) | def is_similar(str1, str2, similarity_threshold=0.9) -> bool:
  function count_ratio (line 401) | def count_ratio(str1, str2) -> float:

FILE: gpt_engineer/core/files_dict.py
  class FilesDict (line 19) | class FilesDict(dict):
    method __setitem__ (line 29) | def __setitem__(self, key: Union[str, Path], value: str):
    method to_chat (line 55) | def to_chat(self):
    method to_log (line 74) | def to_log(self):
  function file_to_lines_dict (line 92) | def file_to_lines_dict(file_content: str) -> dict:

FILE: gpt_engineer/core/git.py
  function is_git_installed (line 10) | def is_git_installed():
  function is_git_repo (line 14) | def is_git_repo(path: Path):
  function init_git_repo (line 26) | def init_git_repo(path: Path):
  function has_uncommitted_changes (line 30) | def has_uncommitted_changes(path: Path):
  function filter_files_with_uncommitted_changes (line 41) | def filter_files_with_uncommitted_changes(
  function stage_files (line 54) | def stage_files(path: Path, files: List[str]):
  function filter_by_gitignore (line 58) | def filter_by_gitignore(path: Path, file_list: List[str]) -> List[str]:
  function stage_uncommitted_to_git (line 71) | def stage_uncommitted_to_git(path, files_dict, improve_mode):

FILE: gpt_engineer/core/linting.py
  class Linting (line 6) | class Linting:
    method __init__ (line 7) | def __init__(self):
    method lint_python (line 13) | def lint_python(self, content, config):
    method lint_files (line 31) | def lint_files(self, files_dict: FilesDict, config: dict = None) -> Fi...

FILE: gpt_engineer/core/preprompts_holder.py
  class PrepromptsHolder (line 7) | class PrepromptsHolder:
    method __init__ (line 24) | def __init__(self, preprompts_path: Path):
    method get_preprompts (line 27) | def get_preprompts(self) -> Dict[str, str]:

FILE: gpt_engineer/core/project_config.py
  class _PathsConfig (line 35) | class _PathsConfig:
  class _RunConfig (line 41) | class _RunConfig:
  class _OpenApiConfig (line 49) | class _OpenApiConfig:
  class _GptEngineerAppConfig (line 54) | class _GptEngineerAppConfig:
  function filter_none (line 59) | def filter_none(d: dict) -> dict:
  class Config (line 73) | class Config:
    method from_toml (line 81) | def from_toml(cls, config_file: Path | str):
    method from_dict (line 88) | def from_dict(cls, config_dict: dict):
    method to_dict (line 111) | def to_dict(self) -> dict:
    method to_toml (line 122) | def to_toml(self, config_file: Path | str, save=True) -> str:
  function read_config (line 154) | def read_config(config_file: Path) -> tomlkit.TOMLDocument:

FILE: gpt_engineer/core/prompt.py
  class Prompt (line 6) | class Prompt:
    method __init__ (line 7) | def __init__(
    method __repr__ (line 17) | def __repr__(self):
    method to_langchain_content (line 20) | def to_langchain_content(self):
    method to_dict (line 36) | def to_dict(self):
    method to_json (line 43) | def to_json(self):

FILE: gpt_engineer/core/token_usage.py
  class TokenUsage (line 32) | class TokenUsage:
  class Tokenizer (line 67) | class Tokenizer:
    method __init__ (line 72) | def __init__(self, model_name):
    method num_tokens (line 80) | def num_tokens(self, txt: str) -> int:
    method num_tokens_for_base64_image (line 96) | def num_tokens_for_base64_image(
    method num_tokens_from_messages (line 142) | def num_tokens_from_messages(self, messages: List[Message]) -> int:
  class TokenUsageLog (line 180) | class TokenUsageLog:
    method __init__ (line 185) | def __init__(self, model_name):
    method update_log (line 193) | def update_log(self, messages: List[Message], answer: str, step_name: ...
    method log (line 226) | def log(self) -> List[TokenUsage]:
    method format_log (line 237) | def format_log(self) -> str:
    method is_openai_model (line 251) | def is_openai_model(self) -> bool:
    method total_tokens (line 262) | def total_tokens(self) -> int:
    method usage_cost (line 273) | def usage_cost(self) -> float | None:

FILE: gpt_engineer/core/version_manager.py
  class BaseVersionManager (line 15) | class BaseVersionManager(ABC):
    method __init__ (line 25) | def __init__(self, path: Union[str, Path]):
    method snapshot (line 29) | def snapshot(self, files_dict: FilesDict) -> str:

FILE: gpt_engineer/tools/custom_steps.py
  function get_platform_info (line 22) | def get_platform_info() -> str:
  function self_heal (line 40) | def self_heal(
  function clarified_gen (line 122) | def clarified_gen(
  function lite_gen (line 198) | def lite_gen(

FILE: projects/example-improve/controller.py
  class Controller (line 4) | class Controller:
    method __init__ (line 5) | def __init__(self, game, view):
    method handle_input (line 9) | def handle_input(self):

FILE: projects/example-improve/main.py
  function main (line 6) | def main():

FILE: projects/example-improve/model.py
  class Point (line 7) | class Point:
  class Game (line 12) | class Game:
    method __init__ (line 13) | def __init__(self):
    method generate_food (line 18) | def generate_food(self):
    method update (line 21) | def update(self):

FILE: projects/example-improve/view.py
  class View (line 4) | class View:
    method __init__ (line 5) | def __init__(self, game):
    method render (line 8) | def render(self):

FILE: scripts/clean_benchmarks.py
  function main (line 17) | def main():

FILE: scripts/legacy_benchmark.py
  function main (line 22) | def main(
  function generate_report (line 97) | def generate_report(benchmarks, benchmark_path):
  function to_emoji (line 136) | def to_emoji(value: bool) -> str:
  function insert_markdown_section (line 155) | def insert_markdown_section(file_path, section_title, section_text, level):
  function ask_yes_no (line 199) | def ask_yes_no(question: str) -> bool:

FILE: scripts/print_chat.py
  function pretty_print_conversation (line 15) | def pretty_print_conversation(messages):
  function main (line 58) | def main(

FILE: scripts/test_api.py
  function post_data (line 8) | def post_data(url, extra_arguments):

FILE: tests/applications/cli/test_cli_agent.py
  function test_init_standard_config (line 20) | def test_init_standard_config(monkeypatch):
  function test_init_lite_config (line 50) | def test_init_lite_config(monkeypatch):
  function test_init_clarified_gen_config (line 83) | def test_init_clarified_gen_config(monkeypatch):
  function test_improve_standard_config (line 115) | def test_improve_standard_config(monkeypatch):

FILE: tests/applications/cli/test_collection_consent.py
  function cleanup (line 18) | def cleanup():
  function test_check_consent_file_exists_and_true (line 33) | def test_check_consent_file_exists_and_true(cleanup):
  function test_check_consent_file_exists_and_false (line 38) | def test_check_consent_file_exists_and_false(cleanup):
  function test_check_consent_file_not_exists_and_user_says_yes (line 44) | def test_check_consent_file_not_exists_and_user_says_yes(cleanup):
  function test_check_consent_file_not_exists_and_user_says_no (line 51) | def test_check_consent_file_not_exists_and_user_says_no(cleanup):
  function test_ask_collection_consent_yes (line 76) | def test_ask_collection_consent_yes(cleanup):
  function test_ask_collection_consent_no (line 84) | def test_ask_collection_consent_no(cleanup):
  function test_ask_collection_consent_invalid_then_yes (line 91) | def test_ask_collection_consent_invalid_then_yes(cleanup):
  function test_ask_collection_consent_invalid_then_no (line 99) | def test_ask_collection_consent_invalid_then_no(cleanup):

FILE: tests/applications/cli/test_learning.py
  function test_human_review_input_no_concent_returns_none (line 9) | def test_human_review_input_no_concent_returns_none():
  function test_human_review_input_consent_code_ran_no_comments (line 16) | def test_human_review_input_consent_code_ran_no_comments():
  function test_human_review_input_consent_code_ran_not_perfect_but_useful_no_comments (line 29) | def test_human_review_input_consent_code_ran_not_perfect_but_useful_no_c...
  function test_check_collection_consent_yes (line 42) | def test_check_collection_consent_yes():
  function test_check_collection_consent_no_ask_collection_consent (line 53) | def test_check_collection_consent_no_ask_collection_consent():
  function test_ask_collection_consent_yes (line 64) | def test_ask_collection_consent_yes():
  function test_ask_collection_consent_no (line 71) | def test_ask_collection_consent_no():
  function test_extract_learning (line 78) | def test_extract_learning():
  function test_get_session (line 101) | def test_get_session():

FILE: tests/applications/cli/test_main.py
  function dcommand (line 22) | def dcommand(typer_f, **kwargs):
  class DefaultArgumentsMain (line 61) | class DefaultArgumentsMain:
    method __call__ (line 62) | def __call__(self):
  function input_generator (line 67) | def input_generator():
  class TestMain (line 76) | class TestMain:
    method test_default_settings_generate_project (line 78) | def test_default_settings_generate_project(self, tmp_path, monkeypatch):
    method test_improve_existing_project (line 86) | def test_improve_existing_project(self, tmp_path, monkeypatch):
    method test_improve_existing_project_skip_file_selection (line 96) | def test_improve_existing_project_skip_file_selection(self, tmp_path, ...
    method test_improve_existing_project_diff_timeout (line 111) | def test_improve_existing_project_diff_timeout(self, tmp_path, monkeyp...
    method test_lite_mode_generate_project (line 150) | def test_lite_mode_generate_project(self, tmp_path, monkeypatch):
    method test_clarify_mode_generate_project (line 160) | def test_clarify_mode_generate_project(self, tmp_path, monkeypatch):
    method test_self_heal_mode_generate_project (line 170) | def test_self_heal_mode_generate_project(self, tmp_path, monkeypatch):
    method test_clarify_lite_improve_mode_generate_project (line 179) | def test_clarify_lite_improve_mode_generate_project(self, tmp_path, mo...
  class TestLoadPrompt (line 196) | class TestLoadPrompt:
    method test_load_prompt_existing_file (line 198) | def test_load_prompt_existing_file(self):
    method test_load_prompt_no_file_improve_mode_false (line 215) | def test_load_prompt_no_file_improve_mode_false(self):
    method test_load_prompt_directory_file (line 238) | def test_load_prompt_directory_file(self):
    method test_load_prompt_empty_file (line 252) | def test_load_prompt_empty_file(self):
    method test_load_prompt_no_image_directory (line 276) | def test_load_prompt_no_image_directory(self):

FILE: tests/benchmark/test_BenchConfig.py
  class TestBenchConfig (line 13) | class TestBenchConfig:
    method test_default_values (line 15) | def test_default_values(self):
    method test_specific_values (line 31) | def test_specific_values(self):
    method test_from_dict_valid_dict (line 57) | def test_from_dict_valid_dict(self):
    method test_from_toml_invalid_path (line 84) | def test_from_toml_invalid_path(self):

FILE: tests/core/default/test_disk_execution_env.py
  class TestOnDiskExecutionEnv (line 13) | class TestOnDiskExecutionEnv(unittest.TestCase):
    method setUp (line 14) | def setUp(self):
    method tearDown (line 18) | def tearDown(self):
    method test_successful_execution (line 21) | def test_successful_execution(self):
    method test_missing_entrypoint (line 37) | def test_missing_entrypoint(self):
    method test_keyboard_interrupt_handling (line 43) | def test_keyboard_interrupt_handling(self):
    method test_execution_with_output (line 60) | def test_execution_with_output(self):

FILE: tests/core/default/test_disk_file_repository.py
  function test_DB_operations (line 6) | def test_DB_operations(tmp_path):
  function test_large_files (line 21) | def test_large_files(tmp_path):
  function test_concurrent_access (line 32) | def test_concurrent_access(tmp_path):
  function test_error_messages (line 62) | def test_error_messages(tmp_path):
  class TestOnDiskRepository (line 78) | class TestOnDiskRepository:
    method test_set_and_get_value (line 80) | def test_set_and_get_value(self, tmp_path):
    method test_key_exists (line 90) | def test_key_exists(self, tmp_path):
    method test_fetch_default_value (line 98) | def test_fetch_default_value(self, tmp_path):
    method test_delete_file_or_directory (line 105) | def test_delete_file_or_directory(self, tmp_path):
    method test_iterate_files (line 117) | def test_iterate_files(self, tmp_path):
    method test_key_error (line 131) | def test_key_error(self, tmp_path):
    method test_value_error (line 138) | def test_value_error(self, tmp_path):
    method test_type_error (line 145) | def test_type_error(self, tmp_path):
    method test_large_file_contents (line 152) | def test_large_file_contents(self, tmp_path):

FILE: tests/core/default/test_simple_agent.py
  function test_init (line 15) | def test_init():
  function test_improve (line 41) | def test_improve():

FILE: tests/core/default/test_steps.py
  class TestGenCode (line 79) | class TestGenCode:
    method test_generates_code_using_ai_model (line 81) | def test_generates_code_using_ai_model(self):
    method test_generated_code_saved_to_disk (line 100) | def test_generated_code_saved_to_disk(self):
    method test_raises_type_error_if_keys_not_strings_or_path_objects (line 118) | def test_raises_type_error_if_keys_not_strings_or_path_objects(self):
    method test_raises_type_error_if_values_not_strings (line 133) | def test_raises_type_error_if_values_not_strings(self):
    method test_raises_key_error_if_file_not_exist_in_database (line 148) | def test_raises_key_error_if_file_not_exist_in_database(self):
  class TestStepUtilities (line 163) | class TestStepUtilities:
    method test_called_from_function (line 164) | def test_called_from_function(self):
    method test_constructs_system_prompt_with_predefined_instructions_and_philosophies (line 177) | def test_constructs_system_prompt_with_predefined_instructions_and_phi...
    method test_constructs_system_prompt (line 191) | def test_constructs_system_prompt(self):
  class TestGenEntrypoint (line 206) | class TestGenEntrypoint:
    class MockAI (line 207) | class MockAI:
      method __init__ (line 208) | def __init__(self, content):
      method start (line 211) | def start(self, system, user, step_name):
    method test_valid_input_generates_valid_entrypoint (line 215) | def test_valid_input_generates_valid_entrypoint(self):
    method test_empty_codebase_returns_empty_entrypoint (line 245) | def test_empty_codebase_returns_empty_entrypoint(self):
  class TestImprove (line 268) | class TestImprove:
    method test_improve_existing_code (line 269) | def test_improve_existing_code(self, tmp_path):
    method test_lint_python (line 315) | def test_lint_python(self):
    method test_lint_files (line 322) | def test_lint_files(self):

FILE: tests/core/test_ai.py
  function mock_create_chat_model (line 7) | def mock_create_chat_model(self) -> BaseChatModel:
  function test_start (line 11) | def test_start(monkeypatch):
  function test_next (line 23) | def test_next(monkeypatch):
  function test_token_logging (line 39) | def test_token_logging(monkeypatch):

FILE: tests/core/test_chat_to_files.py
  function test_basic_similarity (line 178) | def test_basic_similarity():
  function test_case_insensitivity_and_whitespace (line 183) | def test_case_insensitivity_and_whitespace():
  function test_length_and_character_frequency (line 188) | def test_length_and_character_frequency():
  function test_edge_cases (line 193) | def test_edge_cases():
  function insert_string_in_lined_string (line 198) | def insert_string_in_lined_string(string, to_insert, line_number):
  function test_diff_changing_one_file (line 204) | def test_diff_changing_one_file():
  function test_diff_adding_one_file (line 212) | def test_diff_adding_one_file():
  function test_diff_changing_two_files (line 220) | def test_diff_changing_two_files():
  function test_validate_diff_correct (line 228) | def test_validate_diff_correct():
  function test_correct_distorted_numbers (line 235) | def test_correct_distorted_numbers():
  function test_correct_skipped_lines (line 244) | def test_correct_skipped_lines():
  function test_correct_skipped_lines_and_number_correction (line 265) | def test_correct_skipped_lines_and_number_correction():
  function test_diff_regex (line 289) | def test_diff_regex():
  function parse_chats_with_regex (line 297) | def parse_chats_with_regex(
  function capture_print_output (line 318) | def capture_print_output(func):
  function test_single_diff (line 329) | def test_single_diff():
  function test_multi_diff_discard (line 335) | def test_multi_diff_discard():
  function test_controller_diff (line 349) | def test_controller_diff():
  function test_simple_calculator_diff (line 353) | def test_simple_calculator_diff():
  function test_complex_temperature_converter_diff (line 357) | def test_complex_temperature_converter_diff():
  function test_complex_task_master_diff (line 361) | def test_complex_task_master_diff():
  function test_long_file_diff (line 365) | def test_long_file_diff():

FILE: tests/core/test_file_selector_enhancements.py
  function set_editor_called (line 11) | def set_editor_called(
  function set_file_selector_tmpproject (line 19) | def set_file_selector_tmpproject(tmp_path):
  function test_file_selector_enhancement_skip_file_selector (line 42) | def test_file_selector_enhancement_skip_file_selector(tmp_path):
  function test_file_selector_enhancement_sort (line 51) | def test_file_selector_enhancement_sort(tmp_path):

FILE: tests/core/test_git.py
  function test_verify_git_installed (line 16) | def test_verify_git_installed():
  function test_init_git_repo (line 21) | def test_init_git_repo():
  function test_stage_files (line 28) | def test_stage_files():
  function test_filter_by_gitignore (line 52) | def test_filter_by_gitignore():
  function test_filter_by_uncommitted_changes (line 63) | def test_filter_by_uncommitted_changes():
  function test_filter_by_uncommitted_changes_ignore_staged_files (line 84) | def test_filter_by_uncommitted_changes_ignore_staged_files():
  function test_filter_by_uncommitted_changes_ignore_untracked (line 98) | def test_filter_by_uncommitted_changes_ignore_untracked():

FILE: tests/core/test_salvage_correct_hunks.py
  function get_file_content (line 19) | def get_file_content(file_path: str) -> str:
  function message_builder (line 26) | def message_builder(chat_path: str) -> List[AIMessage]:
  function test_validation_and_apply_complex_diff (line 46) | def test_validation_and_apply_complex_diff():
  function test_validation_and_apply_long_diff (line 51) | def test_validation_and_apply_long_diff():
  function test_validation_and_apply_wrong_diff (line 56) | def test_validation_and_apply_wrong_diff():
  function test_validation_and_apply_non_change_diff (line 63) | def test_validation_and_apply_non_change_diff():
  function test_validation_and_apply_diff_on_apps_benchmark_6 (line 68) | def test_validation_and_apply_diff_on_apps_benchmark_6():
  function test_validation_and_apply_diff_on_apps_benchmark_6_v2 (line 73) | def test_validation_and_apply_diff_on_apps_benchmark_6_v2():
  function test_create_two_new_files (line 78) | def test_create_two_new_files():
  function test_theo_case (line 83) | def test_theo_case():
  function test_zbf_yml_missing (line 92) | def test_zbf_yml_missing():
  function test_clean_up_folder (line 103) | def test_clean_up_folder(clean_up_folder):
  function clean_up_folder (line 109) | def clean_up_folder():

FILE: tests/core/test_token_usage.py
  function test_format_log (line 15) | def test_format_log():
  function test_usage_cost (line 37) | def test_usage_cost():
  function test_image_tokenizer (line 55) | def test_image_tokenizer():
  function test_list_type_message_with_image (line 80) | def test_list_type_message_with_image():

FILE: tests/mock_ai.py
  class MockAI (line 4) | class MockAI:
    method __init__ (line 5) | def __init__(self, response: List):
    method start (line 8) | def start(self, system: str, user: Any, *, step_name: str) -> List[str]:
    method next (line 11) | def next(

FILE: tests/test_install.py
  function venv_setup_teardown (line 19) | def venv_setup_teardown():
  function test_installation (line 52) | def test_installation():
  function test_cli_execution (line 72) | def test_cli_execution():
  function test_installed_main_execution (line 89) | def test_installed_main_execution(tmp_path, monkeypatch):

FILE: tests/test_project_config.py
  function test_config_load (line 14) | def test_config_load():
  function test_config_defaults (line 45) | def test_config_defaults():
  function test_config_from_dict (line 59) | def test_config_from_dict():
  function test_config_from_dict_with_openapi (line 70) | def test_config_from_dict_with_openapi():
  function test_config_load_partial (line 90) | def test_config_load_partial():
  function test_config_update (line 110) | def test_config_update():
  function test_filter_none (line 143) | def test_filter_none(input_dict, expected):
Condensed preview — 177 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (747K chars).
[
  {
    "path": ".dockerignore",
    "chars": 710,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# Byte-compiled / optimized / DLL files\n__py"
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 30,
    "preview": ".github/workflows/ @ATheorell\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "chars": 5483,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 7056,
    "preview": "# Contributing to gpt-engineer\n\nThe gpt-engineer is a community project and lives from your contributions - they are war"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 85,
    "preview": "# These are supported funding model platforms\n\ngithub: [antonosika]\npatreon: gpt_eng\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "chars": 1132,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug, triage\nassignees: ''\n\n---\n\n## Poli"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation-clarification.md",
    "chars": 641,
    "preview": "---\nname: Documentation improvement\nabout: Inaccuracies, inadequacies in the docs pages\ntitle: ''\nlabels: documentation,"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.md",
    "chars": 636,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement, triage\nassignees: ''\n\n-"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/PULL_REQUEST_TEMPLATE.md",
    "chars": 198,
    "preview": "**YOU MAY DELETE THE ENTIRE TEMPLATE BELOW.**\n\n## How Has This Been Tested?\n\nPlease describe if you have either:\n\n- Gene"
  },
  {
    "path": ".github/workflows/automation.yml",
    "chars": 724,
    "preview": "name: Automation Workflow\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n  issues:\n    types: [opened, edited, reopened]\n  pul"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "chars": 1310,
    "preview": "name: Tox pytest all python versions\n\non:\n  push:\n    branches: [ main ]\n    paths:\n      - gpt_engineer/**\n      - test"
  },
  {
    "path": ".github/workflows/pre-commit.yaml",
    "chars": 328,
    "preview": "name: pre-commit\n\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  pre-commit:\n    runs-on: ubuntu-latest\n\n    "
  },
  {
    "path": ".github/workflows/release.yaml",
    "chars": 1794,
    "preview": "name: Build and publish Python packages to PyPI\n\non:\n  workflow_dispatch:\n  release:\n    types:\n      - published\n\njobs:"
  },
  {
    "path": ".gitignore",
    "chars": 1236,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# Byte-compiled / optimized / DLL files\n__py"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 681,
    "preview": "# See https://pre-commit.com for more information\n# See https://pre-commit.com/hooks.html for more hooks\nfail_fast: true"
  },
  {
    "path": ".readthedocs.yaml",
    "chars": 1033,
    "preview": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html f"
  },
  {
    "path": "Acknowledgements.md",
    "chars": 318,
    "preview": "# We thank the following people for inspiration\n\n| Person | Content | File(s) | Source |\n|----|---|---|---|\n| Paul Gauth"
  },
  {
    "path": "DISCLAIMER.md",
    "chars": 1765,
    "preview": "# Disclaimer\n\ngpt-engineer is an experimental application and is provided \"as-is\" without any warranty, express or impli"
  },
  {
    "path": "GOVERNANCE.md",
    "chars": 4939,
    "preview": "# Governance Model of GPT-Engineer\n\n## I. Project Board Structure\n\n### Project Board\n\nThe Project Board is the central d"
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2023 Anton Osika\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "MANIFEST.in",
    "chars": 44,
    "preview": "recursive-include gpt_engineer/preprompts *\n"
  },
  {
    "path": "Makefile",
    "chars": 2087,
    "preview": "#Sets the default shell for executing commands as /bin/bash and specifies command should be executed in a Bash shell.\nSH"
  },
  {
    "path": "README.md",
    "chars": 7851,
    "preview": "# gpt-engineer\n\n[![GitHub Repo stars](https://img.shields.io/github/stars/gpt-engineer-org/gpt-engineer?style=social)](h"
  },
  {
    "path": "ROADMAP.md",
    "chars": 1343,
    "preview": "# Roadmap\n\n<img width=\"800\" alt=\"image\" src=\"https://github.com/gpt-engineer-org/gpt-engineer/assets/48092564/06bce891-0"
  },
  {
    "path": "TERMS_OF_USE.md",
    "chars": 1910,
    "preview": "# Terms of Use\n\nWelcome to gpt-engineer! By utilizing this powerful tool, you acknowledge and agree to the following com"
  },
  {
    "path": "WINDOWS_README.md",
    "chars": 3584,
    "preview": "# Windows Setup\n## Short version\n\nOn Windows, follow the standard [README.md](https://github.com/gpt-engineer-org/gpt-en"
  },
  {
    "path": "citation.cff",
    "chars": 305,
    "preview": "cff-version: 1.0.0\nmessage: \"If you use this software, please cite it as below.\"\nauthors:\n  - family-names: Osika\n    gi"
  },
  {
    "path": "docker/Dockerfile",
    "chars": 600,
    "preview": "# Stage 1: Builder stage\nFROM python:3.11-slim AS builder\n\nRUN apt-get update && apt-get install -y --no-install-recomme"
  },
  {
    "path": "docker/README.md",
    "chars": 2484,
    "preview": "# Getting Started Using Docker\n\nThis guide provides step-by-step instructions on how to set up and run the Docker enviro"
  },
  {
    "path": "docker/entrypoint.sh",
    "chars": 352,
    "preview": "#!/usr/bin/env bash\n# -*- coding: utf-8 -*-\n\nproject_dir=\"/project\"\n\n# Run the gpt engineer script\ngpt-engineer $project"
  },
  {
    "path": "docker-compose.yml",
    "chars": 359,
    "preview": "services:\n  gpt-engineer:\n    build:\n      context: .\n      dockerfile: docker/Dockerfile\n    stdin_open: true\n    tty: "
  },
  {
    "path": "docs/Makefile",
    "chars": 613,
    "preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHI"
  },
  {
    "path": "docs/api_reference.rst",
    "chars": 3999,
    "preview": ".. _api_reference:\n\n=============\nAPI Reference\n=============\n\n:mod:`gpt_engineer.applications`: Applications\n=========="
  },
  {
    "path": "docs/code_conduct_link.rst",
    "chars": 75,
    "preview": ".. include:: ../.github/CODE_OF_CONDUCT.md\n   :parser: myst_parser.sphinx_\n"
  },
  {
    "path": "docs/conf.py",
    "chars": 6042,
    "preview": "#!/usr/bin/env python\n#\n# file_processor documentation build configuration file, created by\n# sphinx-quickstart on Fri J"
  },
  {
    "path": "docs/contributing_link.rst",
    "chars": 72,
    "preview": ".. include:: ../.github/CONTRIBUTING.md\n   :parser: myst_parser.sphinx_\n"
  },
  {
    "path": "docs/create_api_rst.py",
    "chars": 2480,
    "preview": "\"\"\"Script for auto-generating api_reference.rst\"\"\"\nimport glob\nimport re\n\nfrom pathlib import Path\n\nROOT_DIR = Path(__fi"
  },
  {
    "path": "docs/disclaimer_link.rst",
    "chars": 62,
    "preview": ".. include:: ../DISCLAIMER.md\n   :parser: myst_parser.sphinx_\n"
  },
  {
    "path": "docs/docs_building.md",
    "chars": 2514,
    "preview": "Building Docs with Sphinx\n=========================\n\nThis example shows a basic Sphinx docs project with Read the Docs. "
  },
  {
    "path": "docs/examples/open_llms/README.md",
    "chars": 1511,
    "preview": "# Test that the Open LLM is running\n\nFirst start the server by using only CPU:\n\n```bash\nexport model_path=\"TheBloke/Code"
  },
  {
    "path": "docs/examples/open_llms/langchain_interface.py",
    "chars": 404,
    "preview": "import os\n\nfrom langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler\nfrom langchain_openai import "
  },
  {
    "path": "docs/examples/open_llms/openai_api_interface.py",
    "chars": 481,
    "preview": "import os\n\nfrom openai import OpenAI\n\nclient = OpenAI(\n    base_url=os.getenv(\"OPENAI_API_BASE\"), api_key=os.getenv(\"OPE"
  },
  {
    "path": "docs/index.rst",
    "chars": 640,
    "preview": "Welcome to GPT-ENGINEER's Documentation\n=======================================\n\n.. toctree::\n   :maxdepth: 2\n   :captio"
  },
  {
    "path": "docs/installation.rst",
    "chars": 1679,
    "preview": ".. highlight:: shell\n\n============\nInstallation\n============\n\n\nStable release\n--------------\n\nTo install ``gpt-engineer`"
  },
  {
    "path": "docs/introduction.md",
    "chars": 873,
    "preview": "# Introduction\n``gpt-engineer`` is a project that uses LLMs (such as GPT-4) to automate the process of software engineer"
  },
  {
    "path": "docs/make.bat",
    "chars": 776,
    "preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=python -m"
  },
  {
    "path": "docs/open_models.md",
    "chars": 5986,
    "preview": "Using with open/local models\n============================\n\n**Use `gpte` first with OpenAI models to get a feel for the `"
  },
  {
    "path": "docs/quickstart.rst",
    "chars": 2081,
    "preview": "==========\nQuickstart\n==========\n\nInstallation\n============\n\nTo install LangChain run:\n\n.. code-block:: console\n\n    $ p"
  },
  {
    "path": "docs/roadmap_link.rst",
    "chars": 59,
    "preview": ".. include:: ../ROADMAP.md\n   :parser: myst_parser.sphinx_\n"
  },
  {
    "path": "docs/terms_link.rst",
    "chars": 64,
    "preview": ".. include:: ../TERMS_OF_USE.md\n   :parser: myst_parser.sphinx_\n"
  },
  {
    "path": "docs/tracing_debugging.md",
    "chars": 989,
    "preview": "Tracing and Debugging with Weights and Biases\n============================\n\n## How to store results in Weights & Biases\n"
  },
  {
    "path": "docs/windows_readme_link.rst",
    "chars": 66,
    "preview": ".. include:: ../WINDOWS_README.md\n   :parser: myst_parser.sphinx_\n"
  },
  {
    "path": "gpt_engineer/__init__.py",
    "chars": 160,
    "preview": "# Adding convenience imports to the package\n\n# from gpt_engineer.tools import code_vector_repository\n# from gpt_engineer"
  },
  {
    "path": "gpt_engineer/applications/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gpt_engineer/applications/cli/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gpt_engineer/applications/cli/cli_agent.py",
    "chars": 9024,
    "preview": "\"\"\"\nThis module provides the CliAgent class which manages the lifecycle of code generation and improvement\nusing an AI m"
  },
  {
    "path": "gpt_engineer/applications/cli/collect.py",
    "chars": 5749,
    "preview": "\"\"\"\nModule `collect` - Data Handling and RudderStack Integration\n\nThis module provides functionalities to handle and sen"
  },
  {
    "path": "gpt_engineer/applications/cli/file_selector.py",
    "chars": 19232,
    "preview": "\"\"\"\nfile_selector.py\n\nThis module offers interactive file selection for projects. Leveraging a terminal-based,\ntree-stru"
  },
  {
    "path": "gpt_engineer/applications/cli/learning.py",
    "chars": 9828,
    "preview": "\"\"\"\nThe `learning` module is designed to facilitate the collection and storage of user feedback on the outputs generated"
  },
  {
    "path": "gpt_engineer/applications/cli/main.py",
    "chars": 18368,
    "preview": "\"\"\"\nEntrypoint for the CLI tool.\n\nThis module serves as the entry point for a command-line interface (CLI) tool.\nIt is d"
  },
  {
    "path": "gpt_engineer/benchmark/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gpt_engineer/benchmark/__main__.py",
    "chars": 5163,
    "preview": "\"\"\"\nMain entry point for the benchmarking tool.\n\nThis module provides a command-line interface for running benchmarks us"
  },
  {
    "path": "gpt_engineer/benchmark/bench_config.py",
    "chars": 1983,
    "preview": "from dataclasses import dataclass, field\nfrom pathlib import Path\n\nfrom tomlkit.items import Integer\n\nfrom gpt_engineer."
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/apps/load.py",
    "chars": 4111,
    "preview": "\"\"\"\nModule for loading APPS evaluation tasks.\n\nThis module provides functionality to load tasks for evaluating GPT-based"
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/apps/problem.py",
    "chars": 555,
    "preview": "import json\n\nfrom dataclasses import dataclass\nfrom functools import cached_property\nfrom typing import List\n\n\n@dataclas"
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/apps/problems.py",
    "chars": 98,
    "preview": "# TODO: Pick problems\n# Temporary testing against these problems\nPROBLEM_IDS = list(range(0, 50))\n"
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/gptme/load.py",
    "chars": 4178,
    "preview": "\"\"\"\nModule for loading GPT-Me evaluation tasks.\n\nThis module provides functionality to load tasks for evaluating GPT-bas"
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/load.py",
    "chars": 1407,
    "preview": "\"\"\"\nModule for loading benchmarks.\n\nThis module provides a central point to access different benchmarks by name.\nIt maps"
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/mbpp/load.py",
    "chars": 3739,
    "preview": "\"\"\"\nModule for loading MBPP evaluation tasks.\n\nThis module provides functionality to load tasks for evaluating GPT-based"
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/mbpp/problem.py",
    "chars": 531,
    "preview": "from dataclasses import dataclass\nfrom typing import List\n\n\n@dataclass(frozen=True)\nclass Problem:\n    source_file: int\n"
  },
  {
    "path": "gpt_engineer/benchmark/benchmarks/mbpp/problems.py",
    "chars": 93,
    "preview": "# TODO: Pick problems\n# Temporary testing against these problems\nPROBLEM_IDS = range(0, 100)\n"
  },
  {
    "path": "gpt_engineer/benchmark/default_bench_config.toml",
    "chars": 277,
    "preview": "# For apps, the maximal range is 0:5000 for both train and test\n[apps]\nactive = true\ntest_start_index = 0\ntest_end_index"
  },
  {
    "path": "gpt_engineer/benchmark/run.py",
    "chars": 4603,
    "preview": "\"\"\"\nModule for running benchmarks.\n\nThis module defines functions to run benchmarks using a given agent and to print\nthe"
  },
  {
    "path": "gpt_engineer/benchmark/types.py",
    "chars": 2592,
    "preview": "\"\"\"\nModule defining types used in benchmarking.\n\nThis module contains dataclass definitions for various types used throu"
  },
  {
    "path": "gpt_engineer/core/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gpt_engineer/core/ai.py",
    "chars": 14606,
    "preview": "\"\"\"\nAI Module\n\nThis module provides an AI class that interfaces with language models to perform various tasks such as\nst"
  },
  {
    "path": "gpt_engineer/core/base_agent.py",
    "chars": 1015,
    "preview": "\"\"\"\nBase Agent Module\n\nThis module provides an abstract base class for an agent that interacts with code. It defines the"
  },
  {
    "path": "gpt_engineer/core/base_execution_env.py",
    "chars": 1191,
    "preview": "from abc import ABC, abstractmethod\nfrom subprocess import Popen\nfrom typing import Optional, Tuple\n\nfrom gpt_engineer.c"
  },
  {
    "path": "gpt_engineer/core/base_memory.py",
    "chars": 485,
    "preview": "\"\"\"\nBase Memory Module\n\nThis module provides a type alias for a mutable mapping that represents the base memory structur"
  },
  {
    "path": "gpt_engineer/core/chat_to_files.py",
    "chars": 9228,
    "preview": "\"\"\"\nThis Python script provides functionalities for parsing chat transcripts that contain file paths and code blocks,\nap"
  },
  {
    "path": "gpt_engineer/core/default/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gpt_engineer/core/default/constants.py",
    "chars": 387,
    "preview": "\"\"\"\nModule defining constants used throughout the application.\n\nThis module contains definitions of constants that are u"
  },
  {
    "path": "gpt_engineer/core/default/disk_execution_env.py",
    "chars": 3618,
    "preview": "\"\"\"\nModule for managing the execution environment on the local disk.\n\nThis module provides a class that handles the exec"
  },
  {
    "path": "gpt_engineer/core/default/disk_memory.py",
    "chars": 9680,
    "preview": "\"\"\"\nDisk Memory Module\n==================\n\nThis module provides a simple file-based key-value database system, where key"
  },
  {
    "path": "gpt_engineer/core/default/file_store.py",
    "chars": 1996,
    "preview": "import tempfile\n\nfrom pathlib import Path\nfrom typing import Union\n\nfrom gpt_engineer.core.files_dict import FilesDict\nf"
  },
  {
    "path": "gpt_engineer/core/default/paths.py",
    "chars": 2370,
    "preview": "\"\"\"\nModule defining file system paths used by the application.\n\nThis module contains definitions of file system paths th"
  },
  {
    "path": "gpt_engineer/core/default/simple_agent.py",
    "chars": 3582,
    "preview": "\"\"\"\nModule for defining a simple agent that uses AI to manage code generation and improvement.\n\nThis module provides a c"
  },
  {
    "path": "gpt_engineer/core/default/steps.py",
    "chars": 12190,
    "preview": "\"\"\"\nModule for defining the steps involved in generating and improving code using AI.\n\nThis module provides functions th"
  },
  {
    "path": "gpt_engineer/core/diff.py",
    "chars": 19216,
    "preview": "\"\"\"\nFile Overview:\n\nThis Python module is designed for processing and analyzing diffs in source code files. Diffs repres"
  },
  {
    "path": "gpt_engineer/core/files_dict.py",
    "chars": 3877,
    "preview": "\"\"\"\nFilesDict Module\n\nThis module provides a FilesDict class which is a dictionary-based container for managing code fil"
  },
  {
    "path": "gpt_engineer/core/git.py",
    "chars": 2389,
    "preview": "import shutil\nimport subprocess\n\nfrom pathlib import Path\nfrom typing import List\n\nfrom gpt_engineer.core.files_dict imp"
  },
  {
    "path": "gpt_engineer/core/linting.py",
    "chars": 2564,
    "preview": "import black\n\nfrom gpt_engineer.core.files_dict import FilesDict\n\n\nclass Linting:\n    def __init__(self):\n        # Dict"
  },
  {
    "path": "gpt_engineer/core/preprompts_holder.py",
    "chars": 869,
    "preview": "from pathlib import Path\nfrom typing import Dict\n\nfrom gpt_engineer.core.default.disk_memory import DiskMemory\n\n\nclass P"
  },
  {
    "path": "gpt_engineer/core/project_config.py",
    "chars": 4993,
    "preview": "\"\"\"\nFunctions for reading and writing the `gpt-engineer.toml` configuration file.\n\nThe `gpt-engineer.toml` file is a TOM"
  },
  {
    "path": "gpt_engineer/core/prompt.py",
    "chars": 1162,
    "preview": "import json\n\nfrom typing import Dict, Optional\n\n\nclass Prompt:\n    def __init__(\n        self,\n        text: str,\n      "
  },
  {
    "path": "gpt_engineer/core/token_usage.py",
    "chars": 9643,
    "preview": "import base64\nimport io\nimport logging\nimport math\n\nfrom dataclasses import dataclass\nfrom typing import List, Union\n\nim"
  },
  {
    "path": "gpt_engineer/core/version_manager.py",
    "chars": 917,
    "preview": "\"\"\"\nVersion Manager Module\n\nThis module provides an abstract base class for a version manager that handles the creation "
  },
  {
    "path": "gpt_engineer/preprompts/clarify",
    "chars": 228,
    "preview": "Given some instructions, determine if anything needs to be clarified, do not carry them out.\nYou can make reasonable ass"
  },
  {
    "path": "gpt_engineer/preprompts/entrypoint",
    "chars": 432,
    "preview": "You will get information about a codebase that is currently on disk in the current folder.\nThe user will ask you to writ"
  },
  {
    "path": "gpt_engineer/preprompts/file_format",
    "chars": 496,
    "preview": "You will output the content of each file necessary to achieve the goal, including ALL code.\nRepresent files like so:\n\nFI"
  },
  {
    "path": "gpt_engineer/preprompts/file_format_diff",
    "chars": 1605,
    "preview": "You will output the content of each file necessary to achieve the goal, including ALL code.\nOutput requested code change"
  },
  {
    "path": "gpt_engineer/preprompts/file_format_fix",
    "chars": 498,
    "preview": "Please fix any errors in the code above.\n\nYou will output the content of each new or changed.\nRepresent files like so:\n\n"
  },
  {
    "path": "gpt_engineer/preprompts/generate",
    "chars": 998,
    "preview": "Think step by step and reason yourself to the correct decisions to make sure we get it right.\nFirst lay out the names of"
  },
  {
    "path": "gpt_engineer/preprompts/improve",
    "chars": 1146,
    "preview": "Think step by step and reason yourself to the correct decisions to make sure we get it right.\nMake changes to existing c"
  },
  {
    "path": "gpt_engineer/preprompts/philosophy",
    "chars": 548,
    "preview": "Almost always put different classes in different files.\nAlways use the programming language the user asks for.\nFor Pytho"
  },
  {
    "path": "gpt_engineer/preprompts/roadmap",
    "chars": 165,
    "preview": "You will get instructions for code to write.\nYou will write a very long answer. Make sure that every detail of the archi"
  },
  {
    "path": "gpt_engineer/tools/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gpt_engineer/tools/custom_steps.py",
    "chars": 7725,
    "preview": "from platform import platform\nfrom sys import version_info\nfrom typing import List, Union\n\nfrom langchain.schema import "
  },
  {
    "path": "gpt_engineer/tools/supported_languages.py",
    "chars": 2037,
    "preview": "\"\"\"\nThis module defines the supported programming languages for document chunking.\n\nVariables:\n    SUPPORTED_LANGUAGES ("
  },
  {
    "path": "projects/example-improve/README.md",
    "chars": 1097,
    "preview": "To implement the game Snake in Python using the Model-View-Controller (MVC) design pattern, we will need several classes"
  },
  {
    "path": "projects/example-improve/controller.py",
    "chars": 694,
    "preview": "import keyboard\n\n\nclass Controller:\n    def __init__(self, game, view):\n        self.game = game\n        self.view = vie"
  },
  {
    "path": "projects/example-improve/main.py",
    "chars": 319,
    "preview": "from controller import Controller\nfrom model import Game\nfrom view import View\n\n\ndef main():\n    game = Game()\n    view "
  },
  {
    "path": "projects/example-improve/model.py",
    "chars": 731,
    "preview": "import random\n\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Point:\n    x: int\n    y: int\n\n\nclass Game:\n    def _"
  },
  {
    "path": "projects/example-improve/prompt",
    "chars": 197,
    "preview": "If up is pressed, the snake should turn down and after one step to the right. If down is pressed it should go up. Also, "
  },
  {
    "path": "projects/example-improve/requirements.txt",
    "chars": 17,
    "preview": "keyboard==0.13.5\n"
  },
  {
    "path": "projects/example-improve/run.sh",
    "chars": 165,
    "preview": "# a) Install dependencies\npython3 -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\n\n# b) Run all ne"
  },
  {
    "path": "projects/example-improve/view.py",
    "chars": 485,
    "preview": "from model import Point\n\n\nclass View:\n    def __init__(self, game):\n        self.game = game\n\n    def render(self):\n    "
  },
  {
    "path": "projects/example-vision/navigation.html",
    "chars": 954,
    "preview": "<html>\n    <head></head>\n    <body style=\"margin: 0; padding: 0;\">\n        <div id=\"navigation\" style=\"width: 100%;borde"
  },
  {
    "path": "projects/example-vision/prompt",
    "chars": 55,
    "preview": "Alter the nav so it looks like the ux diagram provided\n"
  },
  {
    "path": "pyproject.toml",
    "chars": 2873,
    "preview": "[tool.poetry]\nname = \"gpt-engineer\"\nversion = \"0.3.1\"\ndescription = \"Specify what you want it to build, the AI asks for "
  },
  {
    "path": "scripts/clean_benchmarks.py",
    "chars": 1111,
    "preview": "\"\"\"\nThis module provides functionality to clean up benchmark directories by removing\nall files and folders except for 'p"
  },
  {
    "path": "scripts/legacy_benchmark.py",
    "chars": 6050,
    "preview": "\"\"\"\nThis module provides functionality to run benchmarks on different folders within\nthe 'benchmark' directory, wait for"
  },
  {
    "path": "scripts/print_chat.py",
    "chars": 1981,
    "preview": "\"\"\"\nThis module provides functionality to print a conversation with messages\ncolored according to the role of the speake"
  },
  {
    "path": "scripts/test_api.py",
    "chars": 1160,
    "preview": "\"\"\"This is just a demo to test api.py.\"\"\"\n\nfrom time import sleep\n\nimport requests\n\n\ndef post_data(url, extra_arguments)"
  },
  {
    "path": "sweep.yaml",
    "chars": 877,
    "preview": "# Sweep AI turns bug fixes & feature requests into code changes (https://sweep.dev)\n# For details on our config file, ch"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/ai_cache.json",
    "chars": 179380,
    "preview": "{\"[{\\\"type\\\": \\\"system\\\", \\\"data\\\": {\\\"content\\\": \\\"You will get instructions for code to write.\\\\nYou will write a very"
  },
  {
    "path": "tests/applications/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/applications/cli/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/applications/cli/test_cli_agent.py",
    "chars": 5284,
    "preview": "import os\nimport tempfile\n\nimport pytest\n\nfrom langchain.schema import AIMessage\n\nfrom gpt_engineer.applications.cli.cli"
  },
  {
    "path": "tests/applications/cli/test_collect.py",
    "chars": 1578,
    "preview": "\"\"\"\nTests the collect_learnings function in the cli/collect module.\n\"\"\"\n\nimport pytest\n\n# def test_collect_learnings(mon"
  },
  {
    "path": "tests/applications/cli/test_collection_consent.py",
    "chars": 3521,
    "preview": "\"\"\"\nTests for the revised data collection consent mechanism in the cli/learning module.\n\"\"\"\n\nfrom pathlib import Path\nfr"
  },
  {
    "path": "tests/applications/cli/test_learning.py",
    "chars": 3330,
    "preview": "from unittest import mock\n\nfrom gpt_engineer.applications.cli import learning\nfrom gpt_engineer.applications.cli.learnin"
  },
  {
    "path": "tests/applications/cli/test_main.py",
    "chars": 15819,
    "preview": "import dataclasses\nimport functools\nimport inspect\nimport os\nimport shutil\nimport tempfile\n\nfrom argparse import Namespa"
  },
  {
    "path": "tests/benchmark/test_BenchConfig.py",
    "chars": 3554,
    "preview": "# Generated by CodiumAI\n\nimport pytest\n\nfrom gpt_engineer.benchmark.bench_config import (\n    AppsConfig,\n    BenchConfi"
  },
  {
    "path": "tests/core/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/core/default/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/core/default/test_disk_execution_env.py",
    "chars": 2849,
    "preview": "import tempfile\nimport unittest\n\nfrom unittest.mock import MagicMock, patch\n\nfrom gpt_engineer.core.default.disk_executi"
  },
  {
    "path": "tests/core/default/test_disk_file_repository.py",
    "chars": 4258,
    "preview": "import pytest\n\nfrom gpt_engineer.core.default.disk_memory import DiskMemory\n\n\ndef test_DB_operations(tmp_path):\n    # Te"
  },
  {
    "path": "tests/core/default/test_simple_agent.py",
    "chars": 2539,
    "preview": "import tempfile\n\nimport pytest\n\nfrom langchain.schema import AIMessage\n\nfrom gpt_engineer.core.default.disk_execution_en"
  },
  {
    "path": "tests/core/default/test_steps.py",
    "chars": 11636,
    "preview": "# Generated by CodiumAI\nimport tempfile\n\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom langchain.schema impor"
  },
  {
    "path": "tests/core/improve_function_test_cases/apps_benchmark_6_chat",
    "chars": 2377,
    "preview": "To implement this program, we will follow a structured approach. We will create a Python script that takes command-line "
  },
  {
    "path": "tests/core/improve_function_test_cases/apps_benchmark_6_code",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/core/improve_function_test_cases/apps_benchmark_6_v2_chat",
    "chars": 535,
    "preview": "```diff\n--- main.py\n+++ main.py\n@@ -8,7 +8,25 @@\n+    # Implementation will be added here\n+    max_damage = max(blows, k"
  },
  {
    "path": "tests/core/improve_function_test_cases/apps_benchmark_6_v2_code",
    "chars": 904,
    "preview": "import sys\n\ndef calculate_min_blows(n, x, blows):\n    \"\"\"\n    Calculate the minimum number of blows to defeat Zmei Goryn"
  },
  {
    "path": "tests/core/improve_function_test_cases/controller_chat",
    "chars": 2415,
    "preview": "Planning:\n\n1. Modify the `handle_input` method within the `Controller` class to change the behavior of the snake when ce"
  },
  {
    "path": "tests/core/improve_function_test_cases/controller_code",
    "chars": 537,
    "preview": "import keyboard\n\n\nclass Controller:\n    def __init__(self, game, view):\n        self.game = game\n        self.view = vie"
  },
  {
    "path": "tests/core/improve_function_test_cases/corrected_diff_from_missing_lines",
    "chars": 492,
    "preview": "--- example.txt\n+++ example.txt\n@@ -12,7 +12,8 @@\n     sample text 1\n     sample text 2\n+    added extra line here\n #\n #"
  },
  {
    "path": "tests/core/improve_function_test_cases/create_two_new_files_chat",
    "chars": 3486,
    "preview": "To implement the requested functionality, we'll create a Python program that processes the input, evaluates the service "
  },
  {
    "path": "tests/core/improve_function_test_cases/create_two_new_files_code",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/core/improve_function_test_cases/simple_calculator_chat",
    "chars": 2882,
    "preview": "I apologize for the oversight. Let's correct the `calculator.py` file with the proper git diff format, ensuring that the"
  },
  {
    "path": "tests/core/improve_function_test_cases/simple_calculator_code",
    "chars": 629,
    "preview": "class Calculator:\n    def add(self, a, b):\n        return a - b  # Logical\n\n    def subtract(self, a, b)\n        return "
  },
  {
    "path": "tests/core/improve_function_test_cases/task_master_chat",
    "chars": 3641,
    "preview": "Apologies for the confusion. Let's correct the issues in the code with the proper git diff format:\n\n```diff\n--- taskmast"
  },
  {
    "path": "tests/core/improve_function_test_cases/task_master_code",
    "chars": 3430,
    "preview": "improt datetime\n\nclass Task:\n    def __init__(self, title, due_date, priority=1):\n        self.title = tile\n        self"
  },
  {
    "path": "tests/core/improve_function_test_cases/temperature_converter_chat",
    "chars": 4117,
    "preview": "Apologies for the confusion. Let's provide the corrected git diff patches for the `temperatureconverter.py` file.\n\n```di"
  },
  {
    "path": "tests/core/improve_function_test_cases/temperature_converter_code",
    "chars": 2165,
    "preview": "class TemperatureConverter\n    def __init__(self, base_temperature=0, scale=\"Celsius\"):\n        self.base_temp = base_te"
  },
  {
    "path": "tests/core/improve_function_test_cases/theo_case_chat",
    "chars": 4181,
    "preview": "To add an entrypoint for running the API through the command line, we will create a new Python script that can be execut"
  },
  {
    "path": "tests/core/improve_function_test_cases/theo_case_code",
    "chars": 570,
    "preview": "# Use an official Python runtime as a parent image\nFROM python:3.9-slim\n\n# Set the working directory in the container\nWO"
  },
  {
    "path": "tests/core/improve_function_test_cases/vgvishesh_example_2_chat",
    "chars": 1801,
    "preview": "To implement a toggle button for switching between dark and light modes, we need to follow these steps:\n\n1. Update the `"
  },
  {
    "path": "tests/core/improve_function_test_cases/vgvishesh_example_2_code",
    "chars": 500,
    "preview": "import React from 'react';\nimport QRCode from 'qrcode.react';\nimport { profiles } from './components/SocialLinks';\nimpor"
  },
  {
    "path": "tests/core/improve_function_test_cases/vgvishesh_example_chat",
    "chars": 400,
    "preview": "Planning:\n........\n\n```diff\n--- src/components/SocialLinks.tsx\n+++ src/components/SocialLinks.tsx\n@@ -1,10 +1,11 @@\n imp"
  },
  {
    "path": "tests/core/improve_function_test_cases/vgvishesh_example_code",
    "chars": 287,
    "preview": "import React from 'react';\n\nexport const SocialLinks: React.FC = () => {\n  const profiles = {\n    linkedIn: 'https://www"
  },
  {
    "path": "tests/core/improve_function_test_cases/wheaties_example_chat",
    "chars": 7572,
    "preview": "Planning:\n\n1. Refactor the DNS logic to ensure that DNS records are created for every server hostname and sent to every "
  },
  {
    "path": "tests/core/improve_function_test_cases/wheaties_example_code",
    "chars": 27881,
    "preview": "using namespace System.Collections.Generic\n\n\nparam(\n    [string]$CsvPath = \"C:\\Powershell\\Files\\tests2.csv\",\n    [switc"
  },
  {
    "path": "tests/core/improve_function_test_cases/zbf_yml_missing_chat",
    "chars": 2683,
    "preview": "To achieve the separation of environments (stage and local) and to use H2 DB for the local environment, we need to make "
  },
  {
    "path": "tests/core/improve_function_test_cases/zbf_yml_missing_code",
    "chars": 302,
    "preview": "spring:\n  datasource:\n    url: jdbc:postgresql://<RDS_ENDPOINT>:5432/<DB_NAME>\n    username: <DB_USERNAME>\n    password:"
  },
  {
    "path": "tests/core/test_ai.py",
    "chars": 1541,
    "preview": "from langchain.chat_models.base import BaseChatModel\nfrom langchain_community.chat_models.fake import FakeListChatModel\n"
  },
  {
    "path": "tests/core/test_chat_to_files.py",
    "chars": 9133,
    "preview": "import os\n\nfrom typing import Dict, Tuple\n\nimport pytest\n\nfrom gpt_engineer.core.chat_to_files import parse_diffs\nfrom g"
  },
  {
    "path": "tests/core/test_file_selector_enhancements.py",
    "chars": 1733,
    "preview": "import os\n\nfrom pathlib import Path\nfrom typing import List, Union\n\nfrom gpt_engineer.applications.cli.file_selector imp"
  },
  {
    "path": "tests/core/test_git.py",
    "chars": 2908,
    "preview": "import subprocess\nimport tempfile\n\nfrom pathlib import Path\n\nfrom gpt_engineer.core.git import (\n    filter_by_gitignore"
  },
  {
    "path": "tests/core/test_salvage_correct_hunks.py",
    "chars": 3788,
    "preview": "import os\nimport shutil\n\nfrom typing import List\n\nimport pytest\n\nfrom langchain_core.messages import AIMessage\n\nfrom gpt"
  },
  {
    "path": "tests/core/test_token_usage.py",
    "chars": 3279,
    "preview": "import base64\nimport csv\nimport io\nimport os\n\nfrom io import StringIO\nfrom pathlib import Path\n\nfrom langchain.schema im"
  },
  {
    "path": "tests/mock_ai.py",
    "chars": 407,
    "preview": "from typing import Any, List, Optional\n\n\nclass MockAI:\n    def __init__(self, response: List):\n        self.responses = "
  },
  {
    "path": "tests/test_install.py",
    "chars": 3398,
    "preview": "\"\"\"\nTests for successful installation of the package.\n\"\"\"\n\nimport shutil\nimport subprocess\nimport sys\nimport venv\n\nfrom "
  },
  {
    "path": "tests/test_project_config.py",
    "chars": 4270,
    "preview": "import tempfile\n\nimport pytest\n\nfrom gpt_engineer.core.project_config import (\n    Config,\n    _GptEngineerAppConfig,\n  "
  },
  {
    "path": "tests/tools/example_snake_files.py",
    "chars": 38343,
    "preview": "PYTHON = \"\"\"\nimport keyboard\nimport random\nfrom dataclasses import dataclass\n\n\nclass View:\n    def __init__(self, game):"
  },
  {
    "path": "tox.ini",
    "chars": 276,
    "preview": "[tox]\nenvlist = py310, py311, py312\n\n[testenv]\nbasepython =\n    py310: python3.10\n    py311: python3.11\n    py312: pytho"
  }
]

About this extraction

This page contains the full source code of the AntonOsika/gpt-engineer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 177 files (676.2 KB), approximately 169.3k tokens, and a symbol index with 417 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!