├── .assets
├── airbyte_embedding_speed.png
├── airbyte_embedding_time.png
├── gradio-screenshot.png
├── sweep-banner-github.png
├── sweep-square.png
├── sweep_modify_gif_small.gif
└── sweeping.gif
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ └── sweep_issue.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── cypress.yml
│ ├── pypi.yml.removed
│ ├── python.yml
│ ├── review.yml
│ └── sweep.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── bin
├── deploy.sh
├── install.sh
├── install_assistant.sh
├── redeploy.sh
├── server
│ ├── install_full.sh
│ ├── install_light.sh
│ └── run.sh
└── startup.sh
├── docker-compose.yml
├── docs
├── .github
│ └── screenshot.png
├── .gitignore
├── README.md
├── Recipes.md
├── components
│ ├── Cards.tsx
│ ├── PRPreview.jsx
│ ├── RepoPreview.jsx
│ ├── ShowMore.jsx
│ ├── counters.module.css
│ └── counters.tsx
├── extension-post-install.md
├── installation.md
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages
│ ├── _app.tsx
│ ├── _meta.json
│ ├── about
│ │ ├── _meta.json
│ │ ├── examples.mdx
│ │ ├── limitations.mdx
│ │ └── roadmap.mdx
│ ├── blogs
│ │ ├── _meta.json
│ │ ├── ai-code-planning.mdx
│ │ ├── ai-unit-tests.mdx
│ │ ├── automate-tech-debt.mdx
│ │ ├── building-code-search.mdx
│ │ ├── chunking-2m-files.mdx
│ │ ├── chunking-improvements.mdx
│ │ ├── file-cache.mdx
│ │ ├── generating-50k-embeddings-with-gte.mdx
│ │ ├── giving-dev-tools.mdx
│ │ ├── gpt-32k-open-source.mdx
│ │ ├── gpt-4-modification.mdx
│ │ ├── index.mdx
│ │ ├── llm-sdk.mdx
│ │ ├── openai-proxy.mdx
│ │ ├── reading-docs.mdx
│ │ ├── refactor-python.mdx
│ │ ├── search-infra.mdx
│ │ ├── soc2.mdx
│ │ ├── super-linter.mdx
│ │ ├── sweeps-core-algo.mdx
│ │ ├── understanding-codebase-with-ctags.mdx
│ │ ├── vector-db-implementation.mdx
│ │ └── zero-downtime-deployment.mdx
│ ├── cli.mdx
│ ├── deployment.mdx
│ ├── deployment.mdx.old
│ ├── faq.mdx
│ ├── getting-started.md
│ ├── index.mdx
│ ├── privacy.mdx
│ ├── usage
│ │ ├── _meta.json
│ │ ├── advanced.mdx
│ │ ├── config.mdx
│ │ └── tutorial.mdx
│ └── videos
│ │ ├── _meta.json
│ │ ├── adding_banner.mdx
│ │ ├── adding_walrus.mdx
│ │ ├── ai_junior_dev_refactors_itself.mdx
│ │ ├── ai_junior_developer_adds_an_easter_egg_to_our_logo.mdx
│ │ └── introducing_sweep.mdx
├── pnpm-lock.yaml
├── public
│ ├── assets
│ │ ├── azure_playground.png
│ │ ├── multi_llm_step.png
│ │ ├── single_llm_step.png
│ │ ├── tutorial
│ │ │ ├── create_issue.gif
│ │ │ ├── github_pat_config.gif
│ │ │ ├── issue_comment.gif
│ │ │ ├── label_issue.gif
│ │ │ ├── merge_conflict.gif
│ │ │ └── pr_comment.gif
│ │ └── youtube_thumbnail.png
│ ├── assistant
│ │ └── sweep_modify_gif_small.gif
│ ├── banner.png
│ ├── covers
│ │ ├── ai-code-planning.png
│ │ ├── ai-unit-tests.png
│ │ ├── automate-tech-debt.png
│ │ ├── building-code-search.png
│ │ ├── chunking-2m-files.png
│ │ ├── chunking-improvements.png
│ │ ├── file-cache.png
│ │ ├── generating-50k-embeddings-with-gte.png
│ │ ├── giving-dev-tools.png
│ │ ├── gpt-32k-open-source.png
│ │ ├── gpt-4-modification.png
│ │ ├── llm-sdk.png
│ │ ├── openai-proxy.png
│ │ ├── reading-docs.png
│ │ ├── refactor-python.png
│ │ ├── search-infra.png
│ │ ├── self-hosting.png
│ │ ├── super-linter.png
│ │ ├── sweeps-core-algo.png
│ │ ├── understanding-codebase-with-ctags.png
│ │ ├── vector-db-implementation.png
│ │ └── zero-downtime-deployment.png
│ ├── deployment
│ │ ├── appid.png
│ │ ├── appsettings.png
│ │ ├── digitalocean_step1.png
│ │ ├── digitalocean_step2.png
│ │ ├── digitalocean_step3.png
│ │ ├── digitalocean_step4.png
│ │ ├── digitalocean_step5.png
│ │ ├── digitalocean_step6.png
│ │ ├── digitalocean_step7.png
│ │ ├── digitalocean_step8.png
│ │ ├── digitalocean_step9.png
│ │ ├── do.png
│ │ ├── events.png
│ │ ├── fcr.png
│ │ ├── graph.png
│ │ ├── graph_pruned.png
│ │ ├── pem.png
│ │ └── tech_debt.png
│ ├── favicon.ico
│ ├── file_cache.py
│ ├── final-sweep-wizard_128x128.png
│ ├── final-sweep-wizard_16x16.png
│ ├── final-sweep-wizard_256x256.png
│ ├── final-sweep-wizard_32x32.png
│ ├── final-sweep-wizard_48x48.png
│ ├── final-sweep-wizard_64x64.png
│ ├── flowchart
│ │ ├── flowchart_1.png
│ │ ├── flowchart_2.png
│ │ ├── flowchart_3.png
│ │ └── flowchart_4.png
│ ├── logo.png
│ ├── modification
│ │ └── drake.jpg
│ ├── og_image.png
│ ├── og_image.svg
│ ├── openai_proxy
│ │ ├── azure_us_east_rate_limits.png
│ │ ├── multi_region_azure_openai_proxy.png
│ │ ├── openai_cost_graph.png
│ │ ├── openai_rate_limits.png
│ │ └── simple_azure_openai_proxy.png
│ ├── redis_vector_db.py
│ ├── resume.pdf
│ ├── sweep-core-algo
│ │ ├── execute.png
│ │ ├── flowchart.png
│ │ ├── flowchart.svg
│ │ ├── inputs.png
│ │ ├── plan.png
│ │ ├── search.png
│ │ ├── sweep_contributions.png
│ │ └── validation.png
│ ├── trunk
│ │ └── executions.png
│ └── tutorial
│ │ ├── comment.png
│ │ ├── congratulations.png
│ │ ├── deployment.png
│ │ ├── final.png
│ │ ├── github_actions.png
│ │ ├── initial.png
│ │ ├── installation.png
│ │ ├── issue.png
│ │ └── new.png
├── sdk
│ ├── README.md
│ ├── pyproject.toml
│ └── src
│ │ ├── __init__.py
│ │ └── agent.py
├── styles
│ └── global.css
├── tailwind.config.js
├── theme.config.tsx
└── tsconfig.json
├── notebooks
├── chunking.ipynb
├── clustering.ipynb
├── graph.ipynb
└── lexical_index.ipynb
├── package-lock.json
├── package.json
├── pyproject.toml
├── pyrightconfig.json
├── redis.conf
├── requirements.txt
├── sweep.yaml
├── sweep_chat
├── .env
├── .eslintrc.json
├── .gitignore
├── .prettierrc.js
├── README.md
├── app
│ ├── api
│ │ └── auth
│ │ │ └── [...nextauth]
│ │ │ └── route.ts
│ ├── c
│ │ └── [messageId]
│ │ │ └── page.tsx
│ ├── favicon.ico
│ ├── global-error.jsx
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── components.json
├── components
│ ├── App.tsx
│ ├── CodeMirrorSuggestionEditor.tsx
│ ├── FeedbackBlock.tsx
│ ├── MessageDisplay.tsx
│ ├── PrValidationStatusesDisplay.tsx
│ ├── PullRequestDisplay.tsx
│ ├── Survey.tsx
│ ├── shared
│ │ ├── ContextSideBar.tsx
│ │ ├── MarkdownRenderer.tsx
│ │ ├── PulsingLoader.tsx
│ │ ├── SnippetBadge.tsx
│ │ └── SnippetSearch.tsx
│ ├── theme-provider.tsx
│ └── ui
│ │ ├── accordion.tsx
│ │ ├── alert.tsx
│ │ ├── autocomplete.tsx
│ │ ├── autoscroll.tsx
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ ├── collapsible.tsx
│ │ ├── command.tsx
│ │ ├── dialog.tsx
│ │ ├── drawer.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── hover-card.tsx
│ │ ├── input.tsx
│ │ ├── label.tsx
│ │ ├── navigation-menu.tsx
│ │ ├── popover.tsx
│ │ ├── resizable.tsx
│ │ ├── scroll-area.tsx
│ │ ├── sheet.tsx
│ │ ├── skeleton.tsx
│ │ ├── slider.tsx
│ │ ├── switch.tsx
│ │ ├── textarea.tsx
│ │ ├── toast.tsx
│ │ ├── toaster.tsx
│ │ └── use-toast.ts
├── cypress.config.ts
├── cypress
│ ├── e2e
│ │ └── spec.cy.ts
│ ├── fixtures
│ │ └── example.json
│ └── support
│ │ ├── commands.ts
│ │ └── e2e.ts
├── instrumentation.ts
├── lib
│ ├── authOptions.ts
│ ├── constants.ts
│ ├── contextManagers.ts
│ ├── parsePullRequest.ts
│ ├── posthog.ts
│ ├── pullUtils.ts
│ ├── str_utils.ts
│ ├── streamingUtils.ts
│ ├── types.ts
│ └── utils.ts
├── next.config.mjs
├── package-lock.json
├── package.json
├── postcss.config.mjs
├── public
│ ├── banner.svg
│ ├── next.svg
│ └── vercel.svg
├── sentry.client.config.ts
├── sentry.edge.config.ts
├── sentry.server.config.ts
├── tailwind.config.ts
└── tsconfig.json
├── sweepai
├── __init__.py
├── agents
│ ├── agent_utils.py
│ ├── analyze_snippets.py
│ ├── assistant_functions.py
│ ├── assistant_wrapper.py
│ ├── assistant_wrapper_test.py
│ ├── complete_code.py
│ ├── complete_code_test.py
│ ├── distill_issue.py
│ ├── image_description_bot.py
│ ├── issue_cleanup_agent.py
│ ├── modify.py
│ ├── modify_utils.py
│ ├── pr_description_bot.py
│ ├── prune_modify_snippets.py
│ ├── question_answerer.py
│ ├── rg_extractor.py
│ ├── search_agent.py
│ ├── summarize_directory.py
│ └── summarize_file.py
├── api.py
├── chat
│ ├── api.py
│ └── search_prompts.py
├── cli.py
├── cli_test.py
├── config
│ ├── __init__.py
│ ├── client.py
│ └── server.py
├── core
│ ├── __init__.py
│ ├── annotate_code_openai.py
│ ├── chat.py
│ ├── context_pruning.py
│ ├── dynamic_context_bot.py
│ ├── entities.py
│ ├── external_searcher.py
│ ├── lexical_search.py
│ ├── on_comment_prompts.py
│ ├── planning_prompts.py
│ ├── post_merge.py
│ ├── pr_reader.py
│ ├── prompts.py
│ ├── pull_request_bot.py
│ ├── reflection_utils.py
│ ├── repo_parsing_utils.py
│ ├── review_annotations.py
│ ├── review_prompts.py
│ ├── review_utils.py
│ ├── snippet_utils.py
│ ├── sweep_bot.py
│ ├── vector_db.py
│ └── viz_utils.py
├── dataclasses
│ ├── check_status.py
│ ├── code_suggestions.py
│ ├── codereview.py
│ ├── comments.py
│ ├── dockerfile_config.py
│ ├── files.py
│ ├── gha_fix.py
│ ├── searchindex.py
│ └── separatedsnippets.py
├── global_threads.py
├── handlers
│ ├── __init__.py
│ ├── create_pr.py
│ ├── on_button_click.py
│ ├── on_button_click_test.py
│ ├── on_check_suite.py
│ ├── on_comment.py
│ ├── on_failing_github_actions.py
│ ├── on_jira_ticket.py
│ ├── on_merge.py
│ ├── on_ticket.py
│ └── review_pr.py
├── logn
│ ├── README.md
│ ├── __init__.py
│ ├── cache.py
│ └── trace_util.py
├── utils
│ ├── __init__.py
│ ├── anthropic_client.py
│ ├── buttons.py
│ ├── buttons_test.py
│ ├── chat_logger.py
│ ├── code_tree.py
│ ├── code_tree_test.py
│ ├── code_validators.py
│ ├── cohere_utils.py
│ ├── comment_utils.py
│ ├── comment_utils_test.py
│ ├── concurrency_utils.py
│ ├── convert_openai_anthropic.py
│ ├── diff.py
│ ├── diff_test.py
│ ├── docker_utils.py
│ ├── docker_utils_test.py
│ ├── event_logger.py
│ ├── file_utils.py
│ ├── fuzzy_diff.py
│ ├── fuzzy_diff_test.py
│ ├── github_utils.py
│ ├── github_utils_test.py
│ ├── hash.py
│ ├── html_extractor.py
│ ├── image_utils.py
│ ├── issue_validator.py
│ ├── majority_vote.py
│ ├── multi_query.py
│ ├── openai_listwise_reranker.py
│ ├── openai_proxy.py
│ ├── openai_proxy_test.py
│ ├── patch_utils.py
│ ├── previous_diff_utils.py
│ ├── progress.py
│ ├── progress_test.py
│ ├── prompt_constructor.py
│ ├── regex_utils.py
│ ├── ripgrep_utils.py
│ ├── safe_pqueue.py
│ ├── scorer.py
│ ├── scorer_test.py
│ ├── search_and_replace.py
│ ├── search_and_replace_test.py
│ ├── slack_utils.py
│ ├── str_utils.py
│ ├── streamable_functions.py
│ ├── ticket_rendering_utils.py
│ ├── ticket_utils.py
│ ├── tiktoken_utils.py
│ ├── timer.py
│ ├── tree_utils.py
│ ├── user_settings.py
│ ├── utils_test.py
│ └── validate_license.py
├── watch.py
└── web
│ ├── event_utils.py
│ ├── events.py
│ ├── health.py
│ ├── health_test.py
│ └── index.html
└── tests
├── __init__.py
├── e2e
├── test_cli_run.py
├── test_file_tests.py
├── test_pr_comment.py
├── test_pr_review.py
├── test_pr_review_comment.py
└── test_sweep_issue.py
├── events
├── create_None_34875225368.pkl
├── create_None_34875316547.pkl
├── create_None_34875548354.pkl
├── create_None_34875679257.pkl
├── issue_closed_11503916179.pkl
├── issue_comment_created_34875231171.pkl
├── issue_comment_created_34875260242.pkl
├── issue_comment_created_34875326442.pkl
├── issue_comment_created_34875330267.pkl
├── issue_comment_created_34875495470.pkl
├── issue_comment_created_34875496046.pkl
├── issue_comment_created_34875575948.pkl
├── issue_comment_created_34875580479.pkl
├── issue_comment_created_34875663842.pkl
├── issue_comment_created_34875664837.pkl
├── issue_comment_created_34875665614.pkl
├── issue_comment_created_34875673952.pkl
├── issue_comment_created_34875674995.pkl
├── issue_comment_created_34875675569.pkl
├── issue_comment_created_34875703608.pkl
├── issue_comment_created_34875703833.pkl
├── issue_comment_created_34875705752.pkl
├── issue_deployed_11503790917.pkl
├── issue_deployed_11503827904.pkl
├── issue_deployed_11503917336.pkl
├── issue_labeled_11503901425.pkl
├── issue_labeled_11503959359.pkl
├── issue_review_requested_11503787821.pkl
├── issue_unlabeled_11503901079.pkl
├── pull_request_closed_34875582679.pkl
├── pull_request_opened_34875229202.pkl
├── pull_request_opened_34875324597.pkl
├── pull_request_opened_34875574148.pkl
├── pull_request_opened_34875703602.pkl
├── push_None_34875568335.pkl
└── push_None_34875697750.pkl
├── jsons
├── e2e_branch_change.json
├── e2e_button_to_green.json
├── e2e_pr_comment.json
├── e2e_pr_review_comment.json
├── merge_webhook.json
├── move_file_comment.json
├── opened_pull.json
├── pr_activate_hey_button.json
├── pull_request_closed.json
├── summaries.json
├── sweep_rules_webhook.json
└── sweep_yaml.json
├── modify_benchmark.py
├── modify_tests
├── modify_test.py
└── test_tabs.py
├── monitor_prod.py
├── notebooks
├── asst.ipynb
├── asst.py
├── graph.ipynb
├── heatmap.ipynb
├── importmagic.ipynb
├── jedi.ipynb
├── logprobs.ipynb
├── rope.ipynb
├── rope_class.ipynb
├── rope_move.ipynb
├── rope_reorder.ipynb
└── src
│ ├── class_refactor.py
│ ├── helpers
│ ├── test2.py
│ └── utils.py
│ ├── jedi_test.py
│ ├── mod1.py
│ ├── mod2.py
│ ├── mod3.py
│ ├── test.py
│ └── test2.py
├── perf
├── concurrent_fastapi.py
└── stress_test.py
├── ping_webhook.py
├── pr_understanding.py
├── redirect_api.py
├── rerun_chat_modify_direct.py
├── rerun_comment_direct.py
├── rerun_fix_github_actions_direct.py
├── rerun_issue.py
├── rerun_issue_direct.py
├── rerun_pr_review_comment_direct.py
├── rerun_review_pr.py
├── search
└── test_lexical_search.py
├── test_code_review.py
├── test_context_pruning.py
├── test_get_circleci_logs_from_pr.py
├── test_get_gha_logs_from_pr.py
├── test_gha_extraction.py
├── test_github_request_exception.py
├── test_jira_ticket.py
├── test_modify_utils.py
├── test_multiline_comment.py
├── test_run_gha.py
├── test_setup_tree.py
└── test_watch.py
/.assets/airbyte_embedding_speed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/.assets/airbyte_embedding_speed.png
--------------------------------------------------------------------------------
/.assets/airbyte_embedding_time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/.assets/airbyte_embedding_time.png
--------------------------------------------------------------------------------
/.assets/gradio-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/.assets/gradio-screenshot.png
--------------------------------------------------------------------------------
/.assets/sweep-banner-github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/.assets/sweep-banner-github.png
--------------------------------------------------------------------------------
/.assets/sweep-square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/.assets/sweep-square.png
--------------------------------------------------------------------------------
/.assets/sweep_modify_gif_small.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/.assets/sweep_modify_gif_small.gif
--------------------------------------------------------------------------------
/.assets/sweeping.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/.assets/sweeping.gif
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | docs/public/**/*.png filter=lfs diff=lfs merge=lfs -text
2 | docs/public/**/*.gif filter=lfs diff=lfs merge=lfs -text
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | contact_links:
2 | - name: Discourse
3 | url: https://community.sweep.dev/
4 | about: Feel free to report bugs and request features here!
5 | - name: Docs
6 | url: https://docs.sweep.dev
7 | about: Check out how to self-deploy Sweep, usage guides and best practices
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/sweep_issue.yml:
--------------------------------------------------------------------------------
1 | name: Sweep Issue
2 | title: 'Sweep: '
3 | description: For small bugs, features, refactors, and tests to be handled by Sweep, an AI-powered junior developer.
4 | labels: sweep
5 | body:
6 | - type: textarea
7 | id: description
8 | attributes:
9 | label: Details
10 | description: Tell Sweep where and what to edit and provide enough context for a new developer to the codebase
11 | placeholder: |
12 | Bugs: The bug might be in ... file. Here are the logs: ...
13 | Features: the new endpoint should use the ... class from ... file because it contains ... logic.
14 | Refactors: We are migrating this function to ... version because ...
15 | - type: input
16 | id: branch
17 | attributes:
18 | label: Branch
19 | description: The branch to work off of (optional)
20 | placeholder: |
21 | main
22 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Purpose
2 |
3 | Please provide a high-level overview of what this pull request aims to achieve.
4 |
5 | # Changes Made
6 |
7 | Please provide a detailed list of the changes made in this pull request.
8 |
9 | 1.
10 | 2.
11 | 3.
12 |
13 | # Additional Notes
14 |
15 | Please provide any additional notes or screenshots here.
16 | When you make a PR, please ping us on Discourse at https://community.sweep.dev/.
17 |
--------------------------------------------------------------------------------
/.github/workflows/sweep.yml:
--------------------------------------------------------------------------------
1 | # name: Sweep Run Code
2 |
3 | # concurrency:
4 | # group: ${{ github.workflow }}-${{ github.ref }}
5 | # cancel-in-progress: true
6 |
7 | # on:
8 | # push:
9 |
10 | # jobs:
11 | # code-quality:
12 | # runs-on: ubuntu-latest
13 | # strategy:
14 | # matrix:
15 | # python-version: ["3.10"]
16 | # # python-version: ["3.10", "3.11"]
17 | # os: [ubuntu-latest]
18 | # outputs:
19 | # cache-key: ${{ steps.cache-dependencies.outputs.cache-key }}
20 | # steps:
21 | # - uses: actions/checkout@v3
22 | # - uses: actions-rs/toolchain@v1
23 | # with:
24 | # profile: minimal
25 | # toolchain: 1.67.0
26 | # override: true
27 | # - uses: Swatinem/rust-cache@v1
28 | # - uses: actions/setup-python@v4
29 | # with:
30 | # python-version: ${{ matrix.python-version }}
31 | # - run: echo "VIRTUAL_ENV=${Python_ROOT_DIR}" >> $GITHUB_ENV
32 | # # if: steps.restore-dependencies.outputs.cache-hit != 'true'
33 | # - run: pip install uv
34 | # # if: steps.restore-dependencies.outputs.cache-hit != 'true'
35 | # - run: uv pip install -r requirements.txt
36 | # # if: steps.restore-dependencies.outputs.cache-hit != 'true'
37 | # - run: uv pip install ruff pylint pytest pytest-xdist black
38 | # # if: steps.restore-dependencies.outputs.cache-hit != 'true'
39 | # - name: Run arbitrary code
40 | # run: |
41 | # echo "Placeholder"
42 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # See https://pre-commit.com for more information
2 | # See https://pre-commit.com/hooks.html for more hooks
3 | repos:
4 | - repo: https://github.com/pre-commit/pre-commit-hooks
5 | rev: v4.4.0
6 | hooks:
7 | - id: trailing-whitespace
8 | - id: end-of-file-fixer
9 | - id: check-yaml
10 | # - id: check-added-large-files
11 |
12 | - repo: https://github.com/psf/black
13 | rev: 23.9.1
14 | hooks:
15 | - id: black
16 | language_version: python3.10
17 |
18 | - repo: https://github.com/pre-commit/mirrors-isort
19 | rev: v5.10.1 # Use the ref you want to point at
20 | hooks:
21 | - id: isort
22 |
23 | - repo: https://github.com/myint/autoflake
24 | rev: v1.4 # Use the ref you want to point at
25 | hooks:
26 | - id: autoflake
27 | args: ['--remove-all-unused-imports', '--remove-unused-variables', '--in-place']
28 | exclude: '__init__.py'
29 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Contributing to Sweep AI
4 |
5 | First off, thank you for considering contributing to Sweep AI. It's people like you that make Sweep AI such a great tool.
6 |
7 | ## Creating Issues
8 |
9 | Before you submit an issue, please do a search in [open issues](https://github.com/sweepai/sweep/issues) to see if the issue or feature request has already been filed.
10 | Use the provided issue template when creating a new issue. Fill in the template with as much detail as possible. The more detail you provide, the more likely that someone can help you.
11 | Alternatively, you can use Sweep to create a ticket for the problem first. Simply describe the issue or feature request, and Sweep will create a ticket for it. This can help you understand the problem better and guide you in manually solving it.
12 | You can also use Sweep to create tickets. Simply describe the issue or feature request, and Sweep will create a ticket for it.
13 |
14 | ## Submitting Pull Requests
15 |
16 | If you're working on an existing issue, respond to the issue and express interest in working on it. This helps other people know that the issue is active, and hopefully prevents duplicated efforts.
17 |
18 | To submit a pull request, follow the following steps:
19 |
20 | 1. Clone the repository.
21 | 2. Create a new branch from `main`.
22 | 3. Make your changes.
23 | 4. Push your branch and submit a pull request to the `main` branch.
24 | 5. Await review. Respond to any comments or requests made by reviewers.
25 |
26 | ## Important Notes
27 | 1. Please do not edit the structure of the repo. Sweep is constantly changing, and we want to make sure that we can easily integrate your changes into our codebase.
28 |
29 | ## Coding Standards
30 |
31 | Please ensure your code adheres to the coding standards used throughout the project. This includes proper indentation, accurate comments, and clear, concise code.
32 |
33 | ## Community
34 |
35 | Please be respectful and considerate of others. We're all here to learn and grow, so constructive, respectful communication is encouraged.
36 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10-slim as base
2 |
3 | ENV PYTHONDONTWRITEBYTECODE 1
4 | ENV PYTHONUNBUFFERED 1
5 | ENV WORKERS=3
6 | ENV PORT=${PORT:-8080}
7 |
8 | WORKDIR /app
9 |
10 | RUN apt-get update \
11 | && apt-get install -y --no-install-recommends git curl redis-server npm build-essential pkg-config libssl-dev \
12 | cmake pkg-config libicu-dev zlib1g-dev libcurl4-openssl-dev libssl-dev ruby-dev \
13 | && apt-get clean \
14 | && rm -rf /var/lib/apt/lists/*
15 |
16 | RUN gem install github-linguist
17 |
18 | RUN curl -LO https://github.com/BurntSushi/ripgrep/releases/download/13.0.0/ripgrep_13.0.0_amd64.deb && \
19 | dpkg -i ripgrep_13.0.0_amd64.deb && \
20 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
21 | ENV PATH="/root/.cargo/bin:${PATH}"
22 | RUN git clone https://github.com/BurntSushi/ripgrep
23 | RUN cd ripgrep && \
24 | cargo build --release && \
25 | ./target/release/rg --version
26 |
27 | ENV VIRTUAL_ENV=/usr/local
28 | RUN curl -sSL https://astral.sh/uv/install.sh -o /install.sh && chmod 755 /install.sh && /install.sh && rm /install.sh
29 |
30 | COPY requirements.txt ./
31 |
32 | RUN pip install --no-cache -r requirements.txt
33 |
34 | RUN npm install -g prettier@2.0.4 @types/react @types/react-dom typescript eslint@8.57.0
35 | RUN npm install react react-dom
36 | RUN npm install @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-import eslint-plugin-react --save-dev
37 |
38 | COPY sweepai /app/sweepai
39 | COPY tests /app/tests
40 | ENV PYTHONPATH=.
41 | COPY redis.conf /app/redis.conf
42 | COPY bin /app/bin
43 | RUN chmod a+x /app/bin/startup.sh
44 |
45 | EXPOSE 8080
46 | CMD ["bash", "-c", "chmod a+x /app/bin/startup.sh && /app/bin/startup.sh"]
47 |
48 | LABEL org.opencontainers.image.description="Backend for Sweep, an AI-powered junior developer"
49 | LABEL org.opencontainers.image.source="https://github.com/sweepai/sweep"
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Hi everyone!
2 |
3 | Thank you for all of the support on Sweep.
4 | We're now building an AI coding assistant for JetBrains which is available here:
5 | [https://plugins.jetbrains.com/plugin/26275-sweep-ai](https://plugins.jetbrains.com/plugin/26860-sweep-ai)
6 |
--------------------------------------------------------------------------------
/bin/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Remove old docker images only after 2 runs to allow for rollbacks.
4 | # Docker images also need to finish processing their requests before they can be removed.
5 | echo `docker ps`
6 | containers_to_remove=$(docker ps -q | awk 'NR>3')
7 |
8 | if [ ! -z "$containers_to_remove" ]; then
9 | echo "Removing old docker runs"
10 | docker rm -f $containers_to_remove
11 | else
12 | echo "No old docker runs to remove"
13 | fi
14 |
15 | # Find next available port to deploy to
16 | PORT=8081
17 | is_port_free() {
18 | lsof -i :$1 > /dev/null
19 | return $?
20 | }
21 |
22 | while is_port_free $PORT; do
23 | ((PORT++))
24 | done
25 |
26 | echo "Found open port: $PORT"
27 |
28 | # Start new docker container on the next available port
29 | cd ~/sweep
30 | docker build -t sweepai/sweep:latest -f Dockerfile.hosted .
31 | container_id=$(docker run -v /mnt/caches:/mnt/caches -v --env-file .env -p $PORT:8080 -d sweepai/sweep:latest)
32 | docker exec -it $container_id python tests/rerun_issue_direct.py --no-debug https://github.com/wwzeng1/landing-page/issues/114
33 | echo "Running test on https://github.com/wwzeng1/landing-page/issues/114"
34 |
35 | # Wait until webhook is available before rerouting traffic to it
36 | echo "Waiting for server to start..."
37 | while true; do
38 | curl --output /dev/null --silent --fail http://localhost:$PORT/health
39 | if [ $? -eq 0 ]; then
40 | echo "Received a good response!"
41 | break
42 | else
43 | printf '.'
44 | sleep 1
45 | fi
46 | done
47 |
48 | # Update the ngrok proxy to point to the new port
49 | screen -list | grep -q "\bngrok\b"
50 | SESSION_EXISTS=$?
51 |
52 | if [ $SESSION_EXISTS -ne 0 ]; then
53 | screen -S ngrok -d -m
54 | echo creating new session
55 | sleep 1
56 | fi
57 |
58 | # Kill the ngrok process if it's already running
59 | screen -S ngrok -X stuff $'\003'
60 | sleep 1
61 | screen -S ngrok -X stuff $'ngrok http --domain=sweep-prod.ngrok.dev '$PORT$'\n'
62 |
63 | echo "Command sent to screen session on port: $PORT"
64 | echo "To view the ngrok logs, run: screen -r ngrok"
65 |
--------------------------------------------------------------------------------
/bin/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Check if sandbox directory exists, if not clone the repository
3 | if [ ! -d "./sandbox" ]
4 | then
5 | git clone https://github.com/sweepai/sweep-closed sandbox
6 | else
7 | if [ -d "./sandbox/.git" ]
8 | then
9 | echo "Fetching and pulling latest changes from the repository..."
10 | cd sandbox
11 | {
12 | git fetch
13 | git pull
14 | } || {
15 | echo "An error occurred while fetching and pulling the latest changes."
16 | }
17 | cd ..
18 | fi
19 | fi
20 | rm -f poetry.lock
21 | # Check if poetry is installed
22 | if ! command -v poetry &> /dev/null
23 | then
24 | echo "Poetry could not be found, installing..."
25 | curl -sSL https://install.python-poetry.org | python3 -
26 | fi
27 | # Install packages with poetry
28 | echo "Installing packages with poetry..."
29 | poetry install
30 | source $(poetry env info --path)/bin/activate
31 | poetry shell
32 | # Install deeplake with pip
33 | echo "Installing deeplake with pip..."
34 | pip install deeplake
35 | echo "Installing robotexclusionrulesparser with pip..."
36 | pip install robotexclusionrulesparser
37 | echo "Installing e2b with pip..."
38 | pip install e2b
39 | echo "Installing whoosh with pip..."
40 | pip install whoosh
41 | echo "Initializing pre-commits"
42 | pre-commit autoupdate
43 | pre-commit install
44 | echo "Installation complete!"
45 |
--------------------------------------------------------------------------------
/bin/server/install_full.sh:
--------------------------------------------------------------------------------
1 | run_until_success() {
2 | local cmd="$1"
3 | until $cmd; do
4 | echo "Command failed, retrying in 5 seconds..."
5 | sleep 5
6 | done
7 | }
8 |
9 | run_until_success "sudo apt update"
10 | run_until_success "sudo apt install -y gcc g++ curl"
11 | run_until_success "sudo apt-get update"
12 | run_until_success "sudo apt-get install -y redis build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python3-openssl git"
13 | run_until_success "sudo systemctl stop redis"
14 | run_until_success "snap install ngrok"
15 | sudo apt install -y apt-transport-https ca-certificates curl software-properties-common -y && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && sudo apt update -y && sudo apt install docker-ce -y && sudo systemctl enable docker && sudo systemctl start docker && sudo usermod -aG docker ${USER}
16 |
17 | curl https://pyenv.run | bash
18 | {
19 | echo 'export PYENV_ROOT="$HOME/.pyenv"'
20 | echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"'
21 | echo 'eval "$(pyenv init -)"'
22 | echo '. ~/.bashrc'
23 | } > ~/.bash_profile
24 | sed -i '1i\
25 | export PATH="/root/.local/bin:$PATH"\
26 | eval "$(pyenv virtualenv-init -)"\
27 | alias activate='\''source $(poetry env info --path)/bin/activate'\''\
28 | ' ~/.bashrc
29 | source ~/.bash_profile
30 | source ~/.bashrc
31 |
32 | # Install python 3.11.5
33 | pyenv install 3.11.5
34 | cd ~/sweep
35 | pyenv local 3.11.5
36 |
37 | # Install poetry
38 | curl -sSL https://install.python-poetry.org | python3 -
39 | poetry env use /root/.pyenv/versions/3.11.5/bin/python
40 | poetry shell
41 |
42 | # Install with this command, pressing only enter when prompted:
43 | # git clone https://github.com/sweepai/sweep ~/sweep && . sweep/bin/install_full.sh
44 |
45 | # Afterwards, run:
46 | # - poetry install
47 | # - ngrok config (https://dashboard.ngrok.com/get-started/setup)
48 | # - copy .envs
49 |
50 | # To get into poetry shell, run `activate` from the sweep directory.
51 |
--------------------------------------------------------------------------------
/bin/server/install_light.sh:
--------------------------------------------------------------------------------
1 | git clone http://github.com/sweepai/sweep
2 | sudo apt install docker.io -y
3 | sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
4 | sudo chmod +x /usr/local/bin/docker-compose
5 | cd sweep
6 | echo "Configure ngrok: https://dashboard.ngrok.com/get-started/setup"
7 | echo "Then, run docker build/run commands."
8 |
9 | # curl -sSL https://raw.githubusercontent.com/sweepai/sweep/main/bin/server/install_light.sh | bash
10 |
--------------------------------------------------------------------------------
/bin/server/run.sh:
--------------------------------------------------------------------------------
1 | docker run --env-file .env -p 8080:8080 -d sweepai/sweep:latest
2 |
--------------------------------------------------------------------------------
/bin/startup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | RED="\033[0;31m"
4 | GREEN="\033[1;32m"
5 | BLUE="\033[1;34m"
6 | PURPLE="\033[1;35m"
7 | YELLOW="\033[1;33m"
8 | BOLD="\033[1m"
9 | NC="\033[0m" # No Color
10 |
11 | echo "
12 |
13 | @@@@@@%%@@@@@@@
14 | @@ #@
15 | @@ @@@ @@
16 | @ * @ :@
17 | @ =.@ @
18 | -@* # @-
19 | @@@@@@@@@@@@@ @@@@
20 | @@@@@@@@@@@@@ @@@@+ ${PURPLE}Sweep AI GitHub App${NC}
21 | @@ @@ @@@ @@@@@@
22 | @@ @@ @@@@@@@@@@@@@ https://docs.sweep.dev/deployment
23 | @@@@@@@@@@@ @@@@@@@@
24 | @@@@@@@@@ @@@@@@@@
25 | @@@@@@@ @@@@@@.
26 | @@ @@@@@%
27 | @@@@@@ @
28 | @ + @
29 | -@ @ @
30 | @@= @- @
31 | -#
32 | "
33 |
34 |
35 | echo "${BLUE}By using the Sweep GitHub App, you agree to the Sweep AI Terms of Service at https://sweep.dev/tos.pdf${NC}\n"
36 | echo "${YELLOW}You're currently using the free version of self-hosted Sweep AI. For more performance, like fine-tuned search, switch to our enterprise version. Email us at ${BLUE}william@sweep.dev${YELLOW} or schedule a call at ${BLUE}https://calendly.com/sweep-ai/founders-meeting${YELLOW} to get set up.\n"
37 |
38 |
39 | echo "${YELLOW}Launching sweep on https://localhost:${PORT:-8080}${NC}"
40 | redis-server /app/redis.conf --bind 0.0.0.0 --port 6379 > /dev/null 2>&1 &
41 | uvicorn sweepai.api:app --host 0.0.0.0 --port ${PORT:-8080} --workers 8
42 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | hosted:
3 | env_file:
4 | - .env
5 | build:
6 | context: .
7 | dockerfile: Dockerfile
8 | target: base
9 | image: sweepai/sweep
10 | container_name: webhook
11 | # network_mode: "host"
12 | volumes:
13 | - .:/app
14 | - /mnt/caches:/mnt/caches
15 | command: >
16 | sh -c ". bin/startup.sh"
17 | stdin_open: true
18 | tty: true
19 | ports:
20 | - "${PORT:-8080}:8080"
21 | restart: unless-stopped
22 |
--------------------------------------------------------------------------------
/docs/.github/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/docs/.github/screenshot.png
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | .next
2 | node_modules
3 | .env.local
4 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Nextra Docs Template
2 |
3 | This is a template for creating documentation with [Nextra](https://nextra.site).
4 |
5 | [**Live Demo →**](https://nextra-docs-template.vercel.app)
6 |
7 | [](https://nextra-docs-template.vercel.app)
8 |
9 | ## Quick Start
10 |
11 | Click the button to clone this repository and deploy it on Vercel:
12 |
13 | [](https://vercel.com/new/clone?s=https%3A%2F%2Fgithub.com%2Fshuding%2Fnextra-docs-template&showOptionalTeamCreation=false)
14 |
15 | ## Local Development
16 |
17 | First, run `pnpm i` to install the dependencies.
18 |
19 | Then, run `pnpm dev` to start the development server and visit localhost:3000.
20 |
21 | ## License
22 |
23 | This project is licensed under the MIT License.
24 |
--------------------------------------------------------------------------------
/docs/Recipes.md:
--------------------------------------------------------------------------------
1 | ### 🍲 Recipes
2 | #### To get the best performance from Sweep, we recommend the following approach to writing github issues/chats.
3 | For harder problems, try to provide the same information a human would need. For simpler problems, providing a single line and a file name should suffice.
4 |
5 | A good issue might include:
6 |
7 | | Where to look
**[file name or function name]**| What to do
**[change the logic to do this]** | Additional Context (optional)
**[there's a bug/we need this feature/there's this dependency]** |
8 | |-----------|------------|----------------------|
9 | |In `sweepai/app/ui.py`|use an os-agnostic temp directory|N/A|
10 | |In `on_comment.py`|we should not fire an event|because it's possible that the comment is on a closed PR|
11 | |In the config loader in `packages/server/src/config.ts`|add a third option called "env" to load the config settings from environment variables| At present, there are two options: 1. ... and 2. ...|
12 |
13 | If you want Sweep to use a file, try to mention the full path. Similarly, to have Sweep use a function, try to mention the class method or what it does. Also see [✨ Tips and tricks for Sweep](https://docs.sweep.dev/usage/advanced).
14 |
15 | #### Limitations:
16 | Sweep is unlikely to complete complex issues on the first try, similar to the average junior developer. Here are Sweep's limitations(for now):
17 | - Try to change less than 300 lines of code
18 | - Try to modify less than 3 files
19 |
--------------------------------------------------------------------------------
/docs/components/ShowMore.jsx:
--------------------------------------------------------------------------------
1 | import { useState, useRef } from "react"
2 |
3 | export function ShowMore({ children }) {
4 | const [isExpanded, setIsExpanded] = useState(false);
5 | const [showButton, setShowButton] = useState(true);
6 | const contentRef = useRef(null);
7 |
8 | // sort this out later
9 |
10 | // useEffect(() => {
11 | // console.log("contentRef", contentRef.current.scrollHeight)
12 | // if (contentRef.current.scrollHeight < 200) {
13 | // setShowButton(false);
14 | // }
15 | // }, [contentRef]);
16 |
17 | const contentStyle = {
18 | overflow: 'hidden',
19 | transition: 'max-height 0.4s ease-in-out',
20 | maxHeight: (isExpanded || !showButton) ? '5000px' : '300px' // 1000px should be larger than the content's potential maximum height
21 | };
22 |
23 | return (
24 |
25 |
29 | {children}
30 |
31 | {showButton && (
32 |
33 |
36 |
37 | )}
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/docs/components/counters.module.css:
--------------------------------------------------------------------------------
1 | .counter {
2 | border: 1px solid #ccc;
3 | border-radius: 5px;
4 | padding: 2px 6px;
5 | margin: 12px 0 0;
6 | }
7 |
--------------------------------------------------------------------------------
/docs/components/counters.tsx:
--------------------------------------------------------------------------------
1 | // Example from https://beta.reactjs.org/learn
2 |
3 | import { useState } from 'react'
4 | import styles from './counters.module.css'
5 |
6 | function MyButton() {
7 | const [count, setCount] = useState(0)
8 |
9 | function handleClick() {
10 | setCount(count + 1)
11 | }
12 |
13 | return (
14 |
15 |
18 |
19 | )
20 | }
21 |
22 | export default function MyApp() {
23 | return
24 | }
25 |
--------------------------------------------------------------------------------
/docs/extension-post-install.md:
--------------------------------------------------------------------------------
1 | # 🎉 Welcome to Sweep Browser Extension
2 |
3 | Here's how to get started:
4 |
5 | 1. Go to a repo you want to create a Sweep issue on
6 | 2. Click the purple "Make Sweep issue" button (or `ctrl-enter`).
7 | 3. Write the issue title and description and click the submit button (or `ctrl-enter`).
8 |
9 | 
10 |
--------------------------------------------------------------------------------
/docs/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/docs/next.config.js:
--------------------------------------------------------------------------------
1 | const withNextra = require('nextra')({
2 | theme: 'nextra-theme-docs',
3 | themeConfig: './theme.config.tsx',
4 | defaultShowCopyCode: true,
5 | latex: true,
6 | // images: {
7 | // remotePatterns: [
8 | // {
9 | // protocol: 'https',
10 | // hostname: 'raw.githubusercontent.com',
11 | // port: '80',
12 | // pathname: '**',
13 | // },
14 | // ],
15 | // }
16 | })
17 |
18 | module.exports = withNextra()
19 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextra-docs-template",
3 | "version": "0.0.1",
4 | "description": "Nextra docs template",
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/shuding/nextra-docs-template.git"
13 | },
14 | "author": "Shu Ding ",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/shuding/nextra-docs-template/issues"
18 | },
19 | "homepage": "https://github.com/shuding/nextra-docs-template#readme",
20 | "dependencies": {
21 | "@vercel/analytics": "^1.1.2",
22 | "clsx": "^2.1.0",
23 | "diff-parser": "^0.0.1",
24 | "msgpackr": "^1.10.1",
25 | "next": "^14.1.1",
26 | "nextra": "latest",
27 | "nextra-theme-docs": "latest",
28 | "parse-diff": "^0.11.1",
29 | "pug": "^3.0.2",
30 | "react": "^18.2.0",
31 | "react-dom": "^18.2.0",
32 | "react-icons": "^4.12.0",
33 | "react-markdown": "^8.0.7",
34 | "react-youtube": "^10.1.0",
35 | "tailwind": "^4.0.0",
36 | "uglify-js": "2.6.0"
37 | },
38 | "devDependencies": {
39 | "@types/node": "18.11.10",
40 | "typescript": "^4.9.5"
41 | },
42 | "pnpm": {
43 | "overrides": {
44 | "constantinople@<3.1.1": ">=3.1.1",
45 | "clean-css@<4.1.11": ">=4.1.11",
46 | "uglify-js@<2.6.0": ">=2.6.0",
47 | "uglify-js@<2.4.24": ">=2.4.24",
48 | "lodash@<4.17.11": ">=4.17.11",
49 | "ajv@<6.12.3": ">=6.12.3",
50 | "jsonwebtoken@<=8.5.1": ">=9.0.0",
51 | "ws@>=6.0.0 <6.2.2": ">=6.2.2",
52 | "jsonwebtoken@<9.0.0": ">=9.0.0",
53 | "lodash@<4.17.12": ">=4.17.12",
54 | "lodash@<4.17.21": ">=4.17.21",
55 | "moment@>=2.18.0 <2.29.4": ">=2.29.4",
56 | "moment@<2.29.2": ">=2.29.2",
57 | "lodash@>=3.7.0 <4.17.19": ">=4.17.19",
58 | "qs@>=6.5.0 <6.5.3": ">=6.5.3",
59 | "katex@>=0.11.0 <0.16.10": ">=0.16.10",
60 | "katex@>=0.15.4 <0.16.10": ">=0.16.10",
61 | "katex@>=0.10.0-beta <0.16.10": ">=0.16.10",
62 | "express@<4.19.2": ">=4.19.2"
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/docs/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import type { AppProps } from "next/app";
2 | import "../styles/global.css";
3 |
4 |
5 | function MyApp({ Component, pageProps }: AppProps) {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
13 | export default MyApp;
14 |
--------------------------------------------------------------------------------
/docs/pages/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "index": "What's Sweep?",
3 | "getting-started": "🚀 Getting Started",
4 | "cli": "🔧 Sweep CLI",
5 | "deployment": "🏠 Self-Host",
6 | "usage": "📖 Usage",
7 | "about": "👋 About",
8 | "faq": "❓ FAQ",
9 | "blogs": "📚 Blogs",
10 | "videos": "🎥 Videos",
11 | "privacy": "🔒 Privacy Policy",
12 | "home": {
13 | "title": "Home",
14 | "type": "page",
15 | "href": "https://sweep.dev"
16 | },
17 | "email": {
18 | "title": "Email",
19 | "type": "page",
20 | "href": "mailto:team@sweep.dev",
21 | "newWindow": true
22 | },
23 | "community": {
24 | "title": "Community",
25 | "type": "page",
26 | "href": "https://community.sweep.dev",
27 | "newWindow": true
28 | },
29 | "payment": {
30 | "title": "Sweep Pro",
31 | "type": "page",
32 | "href": "https://buy.stripe.com/00g5npeT71H2gzCfZ8",
33 | "newWindow": true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/docs/pages/about/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "examples": "Examples",
3 | "limitations": "Limitations",
4 | "roadmap": "Roadmap"
5 | }
6 |
--------------------------------------------------------------------------------
/docs/pages/about/limitations.mdx:
--------------------------------------------------------------------------------
1 | # ❌ Limitations of Sweep
2 |
3 | - 🔢 Sweep, just like a regular junior developer will likely not get complex issues right first try. Try to keep the tickets to the following sizes. If you break it you’ll likely have to tweak it a lot with PR and code comments.
4 | - 150 lines of code changes
5 | - 3 files modified
6 | - Files with up to 60k characters
7 | - This equates to about 10k tokens, which having in the context and the generation could break the 32k context window
8 | - ⏱️ **Sweep** is powered by GPT-4, so it won't have access to the latest docs and API specs. In the future, it will be able to search for these but for now you can just copy paste the relevant bits into the ticket.
9 | - 📒 Similarly, Sweep’s research capabilities are limited. Bug fixes work only when you have a good idea of the cause of the bug but not before that. Sweep will later have access to terminals and debugging tools but for now it’s only great at tasks where the changes are obvious like adding menu items or moving a function to a different file.
10 | - 🖼️ **Sweep** cannot modify non-code files such as images.
11 |
--------------------------------------------------------------------------------
/docs/pages/about/roadmap.mdx:
--------------------------------------------------------------------------------
1 | # 🗺️ Roadmap
2 |
3 | - 🏖️ Sandbox for code execution. Sweep will be able to run any command you want it to, while developing your code. This allows:
4 | - Pre-commit hooks (automatic linting)
5 | - Deployments to staging environments
6 | - 🧩 Repository wide changes. Sweep will break tasks down into smaller tickets, allowing it to do a lot more work.
7 |
--------------------------------------------------------------------------------
/docs/pages/blogs/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "file-cache": "📂 A better Python cache for slow function calls",
3 | "vector-db-implementation": "🧭 Our simple vector database implementation",
4 | "soc2": "🔒 Sweep's SOC 2 Compliant and Enterprise Offering",
5 | "llm-sdk": "🎉 Releasing our Open Source LLM Framework + Playground!",
6 | "refactor-python": "📝 Large Language Models are Bad at Refactoring Code",
7 | "openai-proxy": "🕸️ A Simple Proxy for Azure and OpenAI raised our GPT4 TPM limit by 24x",
8 | "ai-unit-tests": "🧪 Having GPT-4 Iterate on Unit Tests like a Human",
9 | "zero-downtime-deployment": "🔄 Zero Downtime Deployment with < 50 lines of bash",
10 | "ai-code-planning": "🗺️ How an AI plans code changes across an entire GitHub Repository",
11 | "super-linter": "🛠️ AI Junior Dev meets Super-Linter",
12 | "gpt-4-modification": "🤔 Why getting GPT-4 to modify files is hard",
13 | "automate-tech-debt": "💸 When you should handle tech debt",
14 | "self-hosting": "🏠 Self Hosting an AI Junior Developer",
15 | "chunking-improvements": "📈 Improving LlamaIndex’s Code Chunker by Cleaning Tree-Sitter CSTs",
16 | "reading-docs": "🎓 How our AI junior dev reads all of your documentation",
17 | "sweeps-core-algo": "🧹 Sweep's Core Algorithm",
18 | "generating-50k-embeddings-with-gte": "⚙\uFE0F Generating 50k+ embeddings in 25 seconds using GTE 🧠 and MapReduce 💻",
19 | "chunking-2m-files": "🍪 Chunking 2M+ files a day for Code Search using Syntax Trees",
20 | "giving-dev-tools": "🤖 Letting an AI Junior Dev run GitHub Actions",
21 | "search-infra": "🔍 Code Search Infra for an AI junior developer - that doesn't store code",
22 | "understanding-codebase-with-ctags": "📚 Understanding your codebase with ctags",
23 | "building-code-search": "🏗️ Building a code search engine in one day",
24 | "gpt-32k-open-source": "🌐 GPT 32k, 💻 Open-source, DeepLake 🏞️, GPT Functions Search 🔍 and more!",
25 | "index": "Blogs Gallery"
26 | }
27 |
--------------------------------------------------------------------------------
/docs/pages/blogs/gpt-32k-open-source.mdx:
--------------------------------------------------------------------------------
1 | # **GPT 32k, 💻 Open-source, DeepLake 🏞️, GPT Functions Search 🔍 and more!**
2 |
3 | **Kevin Lu** - July 13th, 2023
4 |
5 | ---
6 |
7 | Excited to announce our latest migrations to GPT 32k and ActiveLoop deep lake, open-sourcing of Sweep and improvements on Sweep’s file search mechanism.
8 |
9 | ## GPT 32k Migration
10 |
11 | GPT 32k (June 13th edition) shows significantly more consistent code generation and instruction-following capabilities, at the cost of a higher price tag and slower PR generation times (2 - 3 min → 5 - 10 min). This drastically reduced some issues we were facing: failure to generate requested changes and failure to follow instructions and respond in specified formats. Expect to see less of “An error has occurred” and more well written PRs. Improving the formats also increases our prompt engineering speed.
12 |
13 | ## Open-sourcing Sweep
14 |
15 | A lot of users were concerned about how we store your source code. We decided that open-sourcing Sweep would provide transparency with how we handle data as well, on top of showing some of the algorithms we use for chunking, indexing, querying and prompting.
16 |
17 | ## ActiveLoop Deep Lake
18 |
19 | Migrating to Deep Lake drastically improved our vector DB’s consistency and reliability, with our previous system being another open-source vector DB library. Deep Lake’s developer interface was also much easier to use, with built-in locking features working well with our serverless Modal backend. There’s still additional work to be done to improve the efficiency like caching embeddings.
20 |
21 | ## GPT Functions Search
22 |
23 | GPT Functions (https://openai.com/blog/function-calling-and-other-api-updates) is basically OpenAI’s interface for more easily creating agents (like ReAct) released yesterday. We integrated GPT Functions into our retrieval system to allow Sweep to decide at runtime whether more search queries should be made. This improves the system by only retrieving more relevant information when needed.
24 |
--------------------------------------------------------------------------------
/docs/pages/blogs/soc2.mdx:
--------------------------------------------------------------------------------
1 | # Sweep is SOC2 Compliant and Enterprise Offering
2 |
3 | *March 6, 2024*
4 |
5 | We’re excited to announce that Sweep has earned SOC2 Type I compliance! This means we’ve passed a third-party audit of our internal security policies and controls that protect customer data.
6 |
7 | The SOC2 Type I audit is globally recognized as a rigorous evaluation of information security practices. Developed by the American Institute of CPAs (AICPA), it allows third-party auditors to assess a service provider's internal controls regarding information security.
8 |
9 | As a product that processes customer code, it’s critical to us that our customer data is protected. In our new enterprise offering, we'll deploy Sweep on your virtual private cloud like AWS, GCP, Azure, or DigitalOcean. This ensures that your code is protected and never enters our servers.
10 |
11 | We'll also finetune our code retrieval models to your codebase. This improves accuracy by up to 20%, saving even more developer time. We also provide usage insights, Sweep progress dashboards, and custom evaluations to understand how Sweep works for your code.
12 |
13 | For a copy of our report, visit [trust portal](https://trust.sweep.dev/).
14 |
--------------------------------------------------------------------------------
/docs/pages/usage/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "tutorial": "Tutorial: Solving an Example Ticket with Sweep",
3 | "advanced": "Advanced Sweep Features: becoming a Power User",
4 | "config": "Config: Customize Sweep using sweep.yaml"
5 | }
6 |
--------------------------------------------------------------------------------
/docs/pages/videos/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "introducing_sweep": "🚀 Introducing Sweep",
3 | "adding_banner": "🖼️ Adding a Banner to our Landing Page using Sweep",
4 | "ai_junior_dev_refactors_itself": "🤖 AI Junior Dev Refactors Itself",
5 | "adding_walrus": "🐋 Adding Walrus Operator to our Code using Sweep",
6 | "ai_junior_developer_adds_an_easter_egg_to_our_logo": "🤖 AI junior developer adds an easter egg to our logo"
7 | }
8 |
--------------------------------------------------------------------------------
/docs/pages/videos/adding_banner.mdx:
--------------------------------------------------------------------------------
1 | import YouTube from 'react-youtube';
2 |
3 | # Adding Banner to our Landing Page with Sweep
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/pages/videos/adding_walrus.mdx:
--------------------------------------------------------------------------------
1 | import YouTube from 'react-youtube';
2 |
3 | # Adding Walrus Operator to our Code with Sweep
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/pages/videos/ai_junior_dev_refactors_itself.mdx:
--------------------------------------------------------------------------------
1 | import YouTube from 'react-youtube';
2 |
3 | # AI Junior Dev Refactors Itself by Writing Code
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/pages/videos/ai_junior_developer_adds_an_easter_egg_to_our_logo.mdx:
--------------------------------------------------------------------------------
1 | import YouTube from 'react-youtube';
2 |
3 | # AI junior developer adds an easter egg to our logo
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/pages/videos/introducing_sweep.mdx:
--------------------------------------------------------------------------------
1 | import YouTube from 'react-youtube';
2 |
3 | # Introducing Sweep - AI powered Bug Fixes and Feature Requests
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/public/assets/azure_playground.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:d571fecee2ad56362902dcb5700ce61042e86abd1d0842f3668fab082149a043
3 | size 595399
4 |
--------------------------------------------------------------------------------
/docs/public/assets/multi_llm_step.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:80260e9ecba568166a5174bc24d860b49bc0650e9b3c986198746623f3d4c1a2
3 | size 34674
4 |
--------------------------------------------------------------------------------
/docs/public/assets/single_llm_step.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e1040ee09cf37c10f6135d2e01ad0cb6657ee57bd3cfb46344dfbd39a1764c46
3 | size 18286
4 |
--------------------------------------------------------------------------------
/docs/public/assets/tutorial/create_issue.gif:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:6a1827febfb03e0132130f18a51c7d53b2beefd08fd7477ea87dd26376fcf11a
3 | size 18763785
4 |
--------------------------------------------------------------------------------
/docs/public/assets/tutorial/github_pat_config.gif:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:66e898adcd3ede9bc042aed0d8d9319040d1b2ba0cff824234c80e4381ec88e8
3 | size 27149651
4 |
--------------------------------------------------------------------------------
/docs/public/assets/tutorial/issue_comment.gif:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f4bd61c8b7421e673e4a383410a874eedc405b319ac5927d829414ec33c7c803
3 | size 11283134
4 |
--------------------------------------------------------------------------------
/docs/public/assets/tutorial/label_issue.gif:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:12072a4ca66bbb7fa78885ef543c666f09afb70d5aa3a0f84d467abb62562fc5
3 | size 6310340
4 |
--------------------------------------------------------------------------------
/docs/public/assets/tutorial/merge_conflict.gif:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:44a004a62eaa262ad7909df25c81335a42ef5484d30d8de6228d435375933efa
3 | size 23603256
4 |
--------------------------------------------------------------------------------
/docs/public/assets/tutorial/pr_comment.gif:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:ad1413b575714dc15364ad9667acd8b751dd0a807364defb9bcf97cb497551cc
3 | size 11207046
4 |
--------------------------------------------------------------------------------
/docs/public/assets/youtube_thumbnail.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:5f67078dfd5ed109fecbc88135556ddbedf20a1e4a3f1f15d2fbf05642d9262b
3 | size 1168916
4 |
--------------------------------------------------------------------------------
/docs/public/assistant/sweep_modify_gif_small.gif:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b6308999b8e7a36e5ed54403597565783fc9f3127d913297f4c06490f9582969
3 | size 13196271
4 |
--------------------------------------------------------------------------------
/docs/public/banner.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2ad65a4ff8180cf4ea69b0ef8a4f43b2a017d171348b94122c7f3fcac4b0f8c6
3 | size 36150
4 |
--------------------------------------------------------------------------------
/docs/public/covers/ai-code-planning.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:03a930ddedc7f300d60cb357b856a3eb0f278e8f2f9cd1a03f3d33a6f5198225
3 | size 2668516
4 |
--------------------------------------------------------------------------------
/docs/public/covers/ai-unit-tests.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f6b7304e260105b7a39b2de9c75143976632e3c941ab5408f3c050b231febed7
3 | size 2712561
4 |
--------------------------------------------------------------------------------
/docs/public/covers/automate-tech-debt.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:478191f639f490b17f5ceaf84f16c2e715810feea3f23f12b8ec190453074334
3 | size 2700277
4 |
--------------------------------------------------------------------------------
/docs/public/covers/building-code-search.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:8735c6b1cfceea937ee4a13e0aa5cc5cec724e07f8dce528ab836d549b8a2ac6
3 | size 3979145
4 |
--------------------------------------------------------------------------------
/docs/public/covers/chunking-2m-files.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c415a1bb7bc2d1a45bcac07ee3b5e60ffd940b48df1e6348b40db49e20dd7e51
3 | size 2401398
4 |
--------------------------------------------------------------------------------
/docs/public/covers/chunking-improvements.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:9da3620f181ec9194b26259caed9afdac3dcc9e5c0a4aa3ced397de9ddc247b0
3 | size 3208322
4 |
--------------------------------------------------------------------------------
/docs/public/covers/file-cache.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:afd84cab5625db59c0bddef7881245946be42c9fe28110122efe518de2c0f4c4
3 | size 180452
4 |
--------------------------------------------------------------------------------
/docs/public/covers/generating-50k-embeddings-with-gte.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:ab8cd5522388dd9f739c3ad9f8c574415de91e31d1087047021e2ecc317e7467
3 | size 3286408
4 |
--------------------------------------------------------------------------------
/docs/public/covers/giving-dev-tools.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:959c44520fd2a39477c5968cacaa41d05a925ca50af6f0413fc94c0f478d9f3f
3 | size 3507755
4 |
--------------------------------------------------------------------------------
/docs/public/covers/gpt-32k-open-source.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:cbb172802508914cbb510f7fbb7452822ff6bbf27b17fb5f3137d337b7a50115
3 | size 3202944
4 |
--------------------------------------------------------------------------------
/docs/public/covers/gpt-4-modification.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:93f6533e1e627c6c9ae6cec2d2e7a6a9d36b96e95353510d3dcd8202b0f08177
3 | size 3370751
4 |
--------------------------------------------------------------------------------
/docs/public/covers/llm-sdk.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:fedb508cbb04567928e639ea556c6195a49b3ad1876aae7de0fde5d10ec9e49e
3 | size 252484
4 |
--------------------------------------------------------------------------------
/docs/public/covers/openai-proxy.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:3f20dd9ac4ae6e2acbbddca76039aaf2c6a77478bce44d5b3ca6098900a81cc5
3 | size 3945641
4 |
--------------------------------------------------------------------------------
/docs/public/covers/reading-docs.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:66e72cab5157de895dbd1f2a0300672e0928b5fc9ed5dabdbd202ac10878d3ae
3 | size 3526119
4 |
--------------------------------------------------------------------------------
/docs/public/covers/refactor-python.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f6d3ffb912043e6725006f3936d3ba8c0183177f49efa68dbdb8f220fe33dc9c
3 | size 1606951
4 |
--------------------------------------------------------------------------------
/docs/public/covers/search-infra.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:6bfcdbcd90da00dc7a528cfee7e71d446b3db9e818230e5b52b0cfd25ec25e8d
3 | size 3217014
4 |
--------------------------------------------------------------------------------
/docs/public/covers/self-hosting.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:245db94e1fff579dac757fb0714370a5048b9b14acb616fb9924d8478dac2b64
3 | size 3169821
4 |
--------------------------------------------------------------------------------
/docs/public/covers/super-linter.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c73518996970293fb9263973feed91031d30e44c4cbf12c61e43e7c0be1a5a6e
3 | size 2534358
4 |
--------------------------------------------------------------------------------
/docs/public/covers/sweeps-core-algo.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:fe4b5188c5624cba149bacc042792fea0c0719417d3babeb22b6720fceb341f0
3 | size 4135636
4 |
--------------------------------------------------------------------------------
/docs/public/covers/understanding-codebase-with-ctags.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:467d0a10f9d99fc3c261d1b88f06da01ce9a67db97c7b8d93c60763fa893fee0
3 | size 2764879
4 |
--------------------------------------------------------------------------------
/docs/public/covers/vector-db-implementation.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:16a2a4eb8fd25422cf9d47d04881cf2f7bd9f9e7cf67186fb2d034a46f349c71
3 | size 176754
4 |
--------------------------------------------------------------------------------
/docs/public/covers/zero-downtime-deployment.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e042f9c54307014eaebfaa41bf71460c4a46f2424cbcc736c354f26bb657593c
3 | size 2164109
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/appid.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:0f64bf48b25a37796efac4104644db41ff0215bb3d8a2da0672611b3534f7b90
3 | size 237386
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/appsettings.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:a1f2bf0d2f1d1ae0017c445fa4a34e49ce5053e8b17f8b6d09bbf9fedf85861b
3 | size 384413
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step1.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:264746b1ac716b981d986831229d848fc41626b6966fde26cedc442c54af3be6
3 | size 130332
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step2.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e581cd4d320203e3fa6ec3c9ebf0bf4875facbe138d471f814be8f456be24a6f
3 | size 151564
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step3.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:273d60408711fb2802b86471e30491ea676340b614b7fd34805051dd859a02a5
3 | size 149321
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step4.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f4404f6543b6c255279f81538aa5b94e54db493c3ee37351ff93aaba1fc948f7
3 | size 149202
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step5.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e48940b086d0ce4b2de6b148f9db2dc78d5237e12c76795d932c73822c502dca
3 | size 212150
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step6.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:ae603e0e1975d777ff025c3f456fbe99848074217a32ea9289f3f4bcf6c8261c
3 | size 28623
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step7.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:da4164b9d7c93bce59ac96cc90b6958fefa510496fa9268aa7b2894837fc8fd1
3 | size 51026
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step8.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2895fbbd5690a0e8e53fa02cb6398e029ab0e87e2e6733ab83b46913ad0d96a5
3 | size 66468
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/digitalocean_step9.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:73efaf76cfdc0609be7fb1346ed84441c6f7221da88cef7a53024861a294c4d1
3 | size 69271
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/do.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b9f57e6cef8b977bb7331b3159cbea71d699ad71384016fc6b1c12acde1c3b79
3 | size 208427
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/events.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:0d4e5d090129cc9e525109afc95267b31bb0611bd4f2685a46118421ce9e9bef
3 | size 208817
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/fcr.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:0006d9fd51e4249651df1d6e097ae8c4a0485d5e1db99e15ff02b1b8c77b9994
3 | size 239545
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/graph.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:fd81e852d73ea7da4d1b1bfe1f887dab53a0907c99b491f0f0f6933bd9291933
3 | size 1655831
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/graph_pruned.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:75517999737810773d850b440ba6167e97cbe190eb17745234934e83b0ea476d
3 | size 2006512
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/pem.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:458e58e0262c9700a0d817e266f685af1cb90281b028063b2264224735d5e305
3 | size 274989
4 |
--------------------------------------------------------------------------------
/docs/public/deployment/tech_debt.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:4f523d4f6a7146cb50c305c2b3f6485cc852e6060b5b338a1cb41a6390e22e2b
3 | size 118563
4 |
--------------------------------------------------------------------------------
/docs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/docs/public/favicon.ico
--------------------------------------------------------------------------------
/docs/public/final-sweep-wizard_128x128.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2ae7bd9f64b1ec870127e062fe01f049642a17150b16c37d9855f55efecb6f58
3 | size 7956
4 |
--------------------------------------------------------------------------------
/docs/public/final-sweep-wizard_16x16.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:32b3912eab3da04cadefa05980d007a2f9c7c549dece81ab772bfbf5db8f0e57
3 | size 686
4 |
--------------------------------------------------------------------------------
/docs/public/final-sweep-wizard_256x256.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:5851286885de6380c0ab61ed1ca6bf1cbb752850379942ef0d1f3eaf0478bf7f
3 | size 17342
4 |
--------------------------------------------------------------------------------
/docs/public/final-sweep-wizard_32x32.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:3fa322896c4ecd9cb3e1ed0434f6737403e05cb4aa91653b97e27fdcacb18e65
3 | size 1586
4 |
--------------------------------------------------------------------------------
/docs/public/final-sweep-wizard_48x48.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:0aff85e1ec866bfe5ae5f97ea69afc036f9765c5daaaf9910d9e0efbe1546333
3 | size 2568
4 |
--------------------------------------------------------------------------------
/docs/public/final-sweep-wizard_64x64.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:cd02c9c77be65303a0dda82bb39356cc0c94e6b9b5be6d1e9442c9d3a43bc4e7
3 | size 3592
4 |
--------------------------------------------------------------------------------
/docs/public/flowchart/flowchart_1.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:cf7b062b9980b3148fd3f2959fa11aee20fc5cc4f504298ee43f799201fb3980
3 | size 32390
4 |
--------------------------------------------------------------------------------
/docs/public/flowchart/flowchart_2.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f58156a1291f8f1c1a1fa63e8618d50315c148a34120c740dce6d1cff2e5c800
3 | size 32103
4 |
--------------------------------------------------------------------------------
/docs/public/flowchart/flowchart_3.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b43e3b821fb3f4c623e3fc5a6b1c3f056540b0d4c7c97a2232b866fadac395f6
3 | size 68578
4 |
--------------------------------------------------------------------------------
/docs/public/flowchart/flowchart_4.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:cf65c06957ba1d049ef96b0c5487a1697117f88682ac98bb1765e243f9968f6e
3 | size 65697
4 |
--------------------------------------------------------------------------------
/docs/public/logo.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b8c98e446703cd4026750332210232a40c0b352e7918d3c4bf0a77f38c4bd7a5
3 | size 32906
4 |
--------------------------------------------------------------------------------
/docs/public/modification/drake.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/docs/public/modification/drake.jpg
--------------------------------------------------------------------------------
/docs/public/og_image.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c2a1e16b979a4341fcdb766073c76bb0a661c1c6fe047db23146996f2ce58ffe
3 | size 44046
4 |
--------------------------------------------------------------------------------
/docs/public/openai_proxy/azure_us_east_rate_limits.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2e35d59a825ba5d767cb184b32c01c1ec0ca2f93676d5878d9a750db3691887e
3 | size 188320
4 |
--------------------------------------------------------------------------------
/docs/public/openai_proxy/multi_region_azure_openai_proxy.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:20731d9fd78b79b10d3f381cad06cae0cafb107d24406c69beceebd910183e56
3 | size 235341
4 |
--------------------------------------------------------------------------------
/docs/public/openai_proxy/openai_cost_graph.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:9aba363776fa4b902fdf6840ee552da3e58ebc54b61d8a8aa6414c119d85cb24
3 | size 11129
4 |
--------------------------------------------------------------------------------
/docs/public/openai_proxy/openai_rate_limits.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:63510e76218e473129c3f6e064927229625dacce0960da84dfc8be984770f657
3 | size 192877
4 |
--------------------------------------------------------------------------------
/docs/public/openai_proxy/simple_azure_openai_proxy.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:fb7ece44673a9decf6eb2ccd4f68578ca507f303297402e21f2dbefbe283593c
3 | size 112863
4 |
--------------------------------------------------------------------------------
/docs/public/resume.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/docs/public/resume.pdf
--------------------------------------------------------------------------------
/docs/public/sweep-core-algo/execute.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:a280ac6cffaa9e14c7a008a0cead6650f688c90736f4ca858d92cda4ee6db008
3 | size 58485
4 |
--------------------------------------------------------------------------------
/docs/public/sweep-core-algo/flowchart.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:952a04414c643dc6caec885ff45934f430feba8c58d58d28862a74b55436924a
3 | size 514850
4 |
--------------------------------------------------------------------------------
/docs/public/sweep-core-algo/inputs.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:216760863294b39d3b2c67ebbb3131256ef34faa11a636efcfb8a305ef10eccf
3 | size 48836
4 |
--------------------------------------------------------------------------------
/docs/public/sweep-core-algo/plan.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:09eb1a83d8626e337dd7738dffeab337971dedfbbb63c5abefc2ae61f56d5f30
3 | size 56456
4 |
--------------------------------------------------------------------------------
/docs/public/sweep-core-algo/search.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e483e399bfb4b84c6d7b92ae50080a61c44f60a351823ee8c344133c57f67be2
3 | size 54551
4 |
--------------------------------------------------------------------------------
/docs/public/sweep-core-algo/sweep_contributions.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c35ffe1cfd4b373f685d4992ff115d1d0d2cff12832f8419e47c35359fb2f6c0
3 | size 28279
4 |
--------------------------------------------------------------------------------
/docs/public/sweep-core-algo/validation.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:77005d03497ca2f294c9b25ece195f5d5e9e59bdc0b9a2230405f0aabc23010f
3 | size 89474
4 |
--------------------------------------------------------------------------------
/docs/public/trunk/executions.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:cf20f50fc428b67c29e1c9218192315f8956cf4f5e1092f3a2efa3399c3a626d
3 | size 96453
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/comment.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2086fd47fa08c18ca6d85ff18e788b7ec55f3b9604f11366c7de8f4a672025d8
3 | size 35657
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/congratulations.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:7107dfbbbb9fb4248efb7b6c415d093e6388e89655f99017a7bdf4c9cf010635
3 | size 214354
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/deployment.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c93343e917e788ca194bab993f5c769dece15bbaa4111945d12ee82cdf65bf05
3 | size 112733
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/final.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:0fdb79379ed365839fd37ad37fa7ca74f7a8bbd495bbfaa3763e81b0a59ed05c
3 | size 33730
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/github_actions.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:4f898fee28bdb337d68d8691dee89c66b689a6ff7dcf7e911622905289919150
3 | size 219640
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/initial.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:5d6406a8d79c5b91ec44971808b10ef401c6fd46a7ed5aba09c32108082753dd
3 | size 50345
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/installation.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:bbb23db976a414325cbaf401a6f77e7ad4d3b7db7f9f1fc45b8a034f811c6265
3 | size 114214
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/issue.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2acb5a3c4383b67ddfff86968914741a303f1296d52459dcd76e8a9a9eb90fdf
3 | size 356043
4 |
--------------------------------------------------------------------------------
/docs/public/tutorial/new.png:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:04337000a5a737e21e35b211f73f4c6bfac44fef93034b9f6436fc1cd66da875
3 | size 50198
4 |
--------------------------------------------------------------------------------
/docs/sdk/README.md:
--------------------------------------------------------------------------------
1 | # Sweep SDK
2 |
3 | Library for building LLM agents.
4 |
--------------------------------------------------------------------------------
/docs/sdk/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "sweep-sdk"
3 | version = "0.0.0"
4 | description = "Python library for building LLM agents"
5 | authors = ["Kevin Lu", "William Zeng"]
6 | packages = [{include = "src" }]
7 | classifiers = ["Programming Language :: Python :: 3.10"]
8 | readme = "README.md"
9 |
10 | [tool.poetry.urls]
11 | Repository = "https://github.com/sweepai/sweep"
12 | "Community" = "https://community.sweep.dev/"
13 | Documentation = "https://docs.sweep.dev"
14 | Homepage = "https://sweep.dev"
15 | "Bug Tracker" = "https://github.com/sweepai/sweep/issues"
16 |
17 | [tool.poetry.dependencies]
18 | python = "^3.10"
19 | backoff = "^2.2.1"
20 | tiktoken = "^0.3.2"
21 | openai = "0.28.1"
22 | loguru = "^0.6.0"
23 |
24 | [tool.black]
25 | string-normalization = false
26 |
27 | [mypy]
28 | check_untyped_defs = true
29 |
30 | [tool.pylint.'MESSAGES CONTROL']
31 |
32 | disable=[
33 | 'no-name-in-module'
34 | ]
35 |
36 | [build-system]
37 | requires = ["poetry-core>=1.0.0"]
38 | build-backend = "poetry.core.masonry.api"
39 |
--------------------------------------------------------------------------------
/docs/sdk/src/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/docs/sdk/src/__init__.py
--------------------------------------------------------------------------------
/docs/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './pages/**/*.{js,jsx,ts,tsx,md,mdx}',
5 | './components/**/*.{js,jsx,ts,tsx,md,mdx}',
6 | ],
7 | theme: {
8 | extend: {}
9 | },
10 | plugins: []
11 | }
12 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "strict": false,
12 | "forceConsistentCasingInFileNames": true,
13 | "noEmit": true,
14 | "incremental": true,
15 | "esModuleInterop": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "jsx": "preserve"
21 | },
22 | "include": [
23 | "next-env.d.ts",
24 | "**/*.m?ts",
25 | "**/*.tsx"
26 | ],
27 | "exclude": [
28 | "node_modules"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next-auth": "^4.24.7",
4 | "react": "^18.2.0",
5 | "react-dom": "^18.2.0"
6 | },
7 | "devDependencies": {
8 | "@typescript-eslint/eslint-plugin": "^7.7.1",
9 | "eslint-plugin-import": "^2.29.1",
10 | "eslint-plugin-react": "^7.34.1",
11 | "prettier": "^2.0.4"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/pyrightconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "exclude": ["**/node_modules", "**/__pycache__", "**/.*"]
3 | }
4 |
--------------------------------------------------------------------------------
/redis.conf:
--------------------------------------------------------------------------------
1 | port 6379
2 | maxmemory 40gb
3 | maxmemory-policy allkeys-lru
4 |
--------------------------------------------------------------------------------
/sweep.yaml:
--------------------------------------------------------------------------------
1 | gha_enabled: True
2 | branch: main
3 | blocked_dirs: ["sweepai/core/prompts.py", "sweep_chat/cypress/e2e/spec.cy.ts"]
4 | draft: False
5 | description: "sweepai/sweep is a python 3.10 project. The main api endpoints are in sweepai/api.py. All imports should be global (like `import sweepai.utils.github_utils`). Write unit tests in the same directory as their corresponding code, i.e. sweepai/api_test.py tests sweepai/api.py. We use pytest for tests. Never use wildcard imports. Use list and tuple for typing instead of typing.List and typing.Tuple."
6 |
7 | rules:
8 | - "We should use loguru for error logging. If the log is inside an exception, use logger.exception to add tracebacks, where logger is imported from loguru. Use f-strings for string formatting in logger calls (e.g. logger.info(f'Hello {name}') instead of logger.info('Hello {name}', name=name))."
9 | - "There should be no debug log or print statements in production code."
10 | - "All functions should have parameters and output annotated with type hints. Use list, tuple and dict instead of typing.List, typing.Tuple and typing.dict."
11 | - "Leftover TODOs in the code should be handled."
12 | - "All new business logic should have corresponding unit tests in the same directory. For example, sweepai/api_test.py tests sweepai/api.py. Use unittest and unittest.mock as required."
13 | - "Any clearly inefficient or repeated code should be optimized or refactored."
14 | - "Remove any comments before code that are obvious. For example `# this prints hello world; print('hello world')`."
15 |
--------------------------------------------------------------------------------
/sweep_chat/.env:
--------------------------------------------------------------------------------
1 | BACKEND_URL=http://127.0.0.1:8000
2 | NEXTAUTH_URL=http://localhost:3000
3 | NEXT_PUBLIC_POSTHOG_KEY="abc"
4 | NEXT_PUBLIC_SENTRY_DSN="https://e6e043ea4f5d0218c35d9066b91fb509@o4507289806635008.ingest.us.sentry.io/4507291374977024"
5 |
--------------------------------------------------------------------------------
/sweep_chat/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/sweep_chat/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
38 | !lib
39 |
40 | # Sentry Config File
41 | .env.sentry-build-plugin
42 |
--------------------------------------------------------------------------------
/sweep_chat/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: false,
3 | singleQuote: false,
4 | tabWidth: 2,
5 | printWidth: 80,
6 | }
7 |
--------------------------------------------------------------------------------
/sweep_chat/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20 |
21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
37 |
--------------------------------------------------------------------------------
/sweep_chat/app/api/auth/[...nextauth]/route.ts:
--------------------------------------------------------------------------------
1 | import authOptions from '@/lib/authOptions'
2 | import NextAuth from 'next-auth'
3 |
4 | const handler = NextAuth(authOptions)
5 |
6 | export { handler as GET, handler as POST }
7 |
--------------------------------------------------------------------------------
/sweep_chat/app/c/[messageId]/page.tsx:
--------------------------------------------------------------------------------
1 | import App from '@/components/App'
2 | import authOptions from '@/lib/authOptions'
3 | import { getServerSession } from 'next-auth'
4 |
5 | export default async function Home({
6 | params,
7 | }: {
8 | params: { messageId: string }
9 | }) {
10 | const session = await getServerSession(authOptions)
11 | return
12 | }
13 |
--------------------------------------------------------------------------------
/sweep_chat/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/sweep_chat/app/favicon.ico
--------------------------------------------------------------------------------
/sweep_chat/app/global-error.jsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as Sentry from '@sentry/nextjs'
4 | import Error from 'next/error'
5 | import { useEffect } from 'react'
6 |
7 | export default function GlobalError({ error }) {
8 | useEffect(() => {
9 | Sentry.captureException(error)
10 | }, [error])
11 |
12 | return (
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/sweep_chat/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from 'next'
2 | import { Inter } from 'next/font/google'
3 | import './globals.css'
4 | import { ThemeProvider } from '@/components/theme-provider'
5 |
6 | const inter = Inter({ subsets: ['latin'] })
7 |
8 | export const metadata: Metadata = {
9 | title: 'Create Next App',
10 | description: 'Generated by create next app',
11 | }
12 |
13 | export default async function RootLayout({
14 | children,
15 | }: Readonly<{
16 | children: React.ReactNode
17 | }>) {
18 | return (
19 |
20 |
21 |
27 | {children}
28 |
29 |
30 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/sweep_chat/app/page.tsx:
--------------------------------------------------------------------------------
1 | import App from '@/components/App'
2 | import authOptions from '@/lib/authOptions'
3 | import { getServerSession } from 'next-auth'
4 |
5 | export default async function Home() {
6 | const session = await getServerSession(authOptions)
7 | return
8 | }
9 |
--------------------------------------------------------------------------------
/sweep_chat/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "default",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.ts",
8 | "css": "app/globals.css",
9 | "baseColor": "zinc",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils"
16 | }
17 | }
--------------------------------------------------------------------------------
/sweep_chat/components/shared/PulsingLoader.tsx:
--------------------------------------------------------------------------------
1 | export default function PulsingLoader({
2 | size = 2,
3 | message,
4 | }: {
5 | size: number
6 | message?: string
7 | }) {
8 | return (
9 |
13 | {message ? message : ''}
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/sweep_chat/components/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import { ThemeProvider as NextThemesProvider } from 'next-themes'
5 | import { type ThemeProviderProps } from 'next-themes/dist/types'
6 |
7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8 | return {children}
9 | }
10 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/accordion.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as AccordionPrimitive from '@radix-ui/react-accordion'
5 | import { ChevronDown } from 'lucide-react'
6 |
7 | import { cn } from '@/lib/utils'
8 |
9 | const Accordion = AccordionPrimitive.Root
10 |
11 | const AccordionItem = React.forwardRef<
12 | React.ElementRef,
13 | React.ComponentPropsWithoutRef
14 | >(({ className, ...props }, ref) => (
15 |
20 | ))
21 | AccordionItem.displayName = 'AccordionItem'
22 |
23 | const AccordionTrigger = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef
26 | >(({ className, children, ...props }, ref) => (
27 |
28 | svg]:rotate-180',
32 | className
33 | )}
34 | {...props}
35 | >
36 | {children}
37 |
38 |
39 |
40 | ))
41 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
42 |
43 | const AccordionContent = React.forwardRef<
44 | React.ElementRef,
45 | React.ComponentPropsWithoutRef
46 | >(({ className, children, ...props }, ref) => (
47 |
52 | {children}
53 |
54 | ))
55 |
56 | AccordionContent.displayName = AccordionPrimitive.Content.displayName
57 |
58 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
59 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/alert.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import { cva, type VariantProps } from 'class-variance-authority'
3 |
4 | import { cn } from '@/lib/utils'
5 |
6 | const alertVariants = cva(
7 | 'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
8 | {
9 | variants: {
10 | variant: {
11 | default: 'bg-background text-foreground',
12 | destructive:
13 | 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
14 | },
15 | },
16 | defaultVariants: {
17 | variant: 'default',
18 | },
19 | }
20 | )
21 |
22 | const Alert = React.forwardRef<
23 | HTMLDivElement,
24 | React.HTMLAttributes & VariantProps
25 | >(({ className, variant, ...props }, ref) => (
26 |
32 | ))
33 | Alert.displayName = 'Alert'
34 |
35 | const AlertTitle = React.forwardRef<
36 | HTMLParagraphElement,
37 | React.HTMLAttributes
38 | >(({ className, ...props }, ref) => (
39 |
44 | ))
45 | AlertTitle.displayName = 'AlertTitle'
46 |
47 | const AlertDescription = React.forwardRef<
48 | HTMLParagraphElement,
49 | React.HTMLAttributes
50 | >(({ className, ...props }, ref) => (
51 |
56 | ))
57 | AlertDescription.displayName = 'AlertDescription'
58 |
59 | export { Alert, AlertTitle, AlertDescription }
60 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/autoscroll.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react'
2 |
3 | import { ScrollArea } from '@/components/ui/scroll-area'
4 |
5 | export default function AutoScrollArea({
6 | children,
7 | className = '',
8 | threshold = Infinity,
9 | }: {
10 | children: React.ReactNode
11 | className?: string
12 | threshold?: number
13 | }) {
14 | const scrollAreaRef = useRef(null)
15 | useEffect(() => {
16 | if (scrollAreaRef.current && scrollAreaRef.current.scrollHeight > 0) {
17 | const { scrollTop, scrollHeight, clientHeight } = scrollAreaRef.current
18 | if (scrollHeight - scrollTop - clientHeight < threshold) {
19 | scrollAreaRef.current.scrollTop = scrollAreaRef.current.scrollHeight
20 | }
21 | }
22 | }, [children])
23 | return (
24 |
25 | {children}
26 |
27 | )
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import { Slot } from '@radix-ui/react-slot'
3 | import { cva, type VariantProps } from 'class-variance-authority'
4 |
5 | import { cn } from '@/lib/utils'
6 |
7 | const buttonVariants = cva(
8 | 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
9 | {
10 | variants: {
11 | variant: {
12 | default: 'bg-primary text-primary-foreground hover:bg-primary/90',
13 | primary: 'bg-blue-900 text-white hover:bg-blue-800',
14 | destructive:
15 | 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
16 | outline:
17 | 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
18 | secondary:
19 | 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
20 | ghost: 'hover:bg-accent hover:text-accent-foreground',
21 | link: 'text-primary underline-offset-4 hover:underline',
22 | },
23 | size: {
24 | default: 'h-10 px-4 py-2',
25 | sm: 'h-9 rounded-md px-3',
26 | lg: 'h-11 rounded-md px-8',
27 | icon: 'h-10 w-10',
28 | },
29 | },
30 | defaultVariants: {
31 | variant: 'default',
32 | size: 'default',
33 | },
34 | }
35 | )
36 |
37 | export interface ButtonProps
38 | extends React.ButtonHTMLAttributes,
39 | VariantProps {
40 | asChild?: boolean
41 | }
42 |
43 | const Button = React.forwardRef(
44 | ({ className, variant, size, asChild = false, ...props }, ref) => {
45 | const Comp = asChild ? Slot : 'button'
46 | return (
47 |
52 | )
53 | }
54 | )
55 | Button.displayName = 'Button'
56 |
57 | export { Button, buttonVariants }
58 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | import { cn } from '@/lib/utils'
4 |
5 | const Card = React.forwardRef<
6 | HTMLDivElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
17 | ))
18 | Card.displayName = 'Card'
19 |
20 | const CardHeader = React.forwardRef<
21 | HTMLDivElement,
22 | React.HTMLAttributes
23 | >(({ className, ...props }, ref) => (
24 |
29 | ))
30 | CardHeader.displayName = 'CardHeader'
31 |
32 | const CardTitle = React.forwardRef<
33 | HTMLParagraphElement,
34 | React.HTMLAttributes
35 | >(({ className, ...props }, ref) => (
36 |
44 | ))
45 | CardTitle.displayName = 'CardTitle'
46 |
47 | const CardDescription = React.forwardRef<
48 | HTMLParagraphElement,
49 | React.HTMLAttributes
50 | >(({ className, ...props }, ref) => (
51 |
56 | ))
57 | CardDescription.displayName = 'CardDescription'
58 |
59 | const CardContent = React.forwardRef<
60 | HTMLDivElement,
61 | React.HTMLAttributes
62 | >(({ className, ...props }, ref) => (
63 |
64 | ))
65 | CardContent.displayName = 'CardContent'
66 |
67 | const CardFooter = React.forwardRef<
68 | HTMLDivElement,
69 | React.HTMLAttributes
70 | >(({ className, ...props }, ref) => (
71 |
76 | ))
77 | CardFooter.displayName = 'CardFooter'
78 |
79 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
80 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/collapsible.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'
4 |
5 | const Collapsible = CollapsiblePrimitive.Root
6 |
7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
8 |
9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
10 |
11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent }
12 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/hover-card.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as HoverCardPrimitive from '@radix-ui/react-hover-card'
5 |
6 | import { cn } from '@/lib/utils'
7 |
8 | const HoverCard = HoverCardPrimitive.Root
9 |
10 | const HoverCardTrigger = HoverCardPrimitive.Trigger
11 |
12 | const HoverCardContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
16 |
26 | ))
27 | HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
28 |
29 | export { HoverCard, HoverCardTrigger, HoverCardContent }
30 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | import { cn } from '@/lib/utils'
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes {}
7 |
8 | const Input = React.forwardRef(
9 | ({ className, type, ...props }, ref) => {
10 | return (
11 |
20 | )
21 | }
22 | )
23 | Input.displayName = 'Input'
24 |
25 | export { Input }
26 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as LabelPrimitive from '@radix-ui/react-label'
5 | import { cva, type VariantProps } from 'class-variance-authority'
6 |
7 | import { cn } from '@/lib/utils'
8 |
9 | const labelVariants = cva(
10 | 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
11 | )
12 |
13 | const Label = React.forwardRef<
14 | React.ElementRef,
15 | React.ComponentPropsWithoutRef &
16 | VariantProps
17 | >(({ className, ...props }, ref) => (
18 |
23 | ))
24 | Label.displayName = LabelPrimitive.Root.displayName
25 |
26 | export { Label }
27 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/popover.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as PopoverPrimitive from '@radix-ui/react-popover'
5 |
6 | import { cn } from '@/lib/utils'
7 |
8 | const Popover = PopoverPrimitive.Root
9 |
10 | const PopoverTrigger = PopoverPrimitive.Trigger
11 |
12 | const PopoverContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
16 |
17 |
27 |
28 | ))
29 | PopoverContent.displayName = PopoverPrimitive.Content.displayName
30 |
31 | export { Popover, PopoverTrigger, PopoverContent }
32 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/resizable.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { GripVertical } from 'lucide-react'
4 | import * as ResizablePrimitive from 'react-resizable-panels'
5 |
6 | import { cn } from '@/lib/utils'
7 |
8 | const ResizablePanelGroup = ({
9 | className,
10 | ...props
11 | }: React.ComponentProps) => (
12 |
19 | )
20 |
21 | const ResizablePanel = ResizablePrimitive.Panel
22 |
23 | const ResizableHandle = ({
24 | withHandle,
25 | className,
26 | ...props
27 | }: React.ComponentProps & {
28 | withHandle?: boolean
29 | }) => (
30 | div]:rotate-90',
33 | className
34 | )}
35 | {...props}
36 | >
37 | {withHandle && (
38 |
39 |
40 |
41 | )}
42 |
43 | )
44 |
45 | export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
46 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/scroll-area.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
5 |
6 | import { cn } from '@/lib/utils'
7 |
8 | const ScrollArea = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, children, ...props }, ref) => (
12 |
17 |
18 | {children}
19 |
20 |
21 |
22 |
23 | ))
24 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
25 |
26 | const ScrollBar = React.forwardRef<
27 | React.ElementRef,
28 | React.ComponentPropsWithoutRef
29 | >(({ className, orientation = 'vertical', ...props }, ref) => (
30 |
43 |
44 |
45 | ))
46 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
47 |
48 | export { ScrollArea, ScrollBar }
49 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/skeleton.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/lib/utils'
2 |
3 | function Skeleton({
4 | className,
5 | ...props
6 | }: React.HTMLAttributes) {
7 | return (
8 |
12 | )
13 | }
14 |
15 | export { Skeleton }
16 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/slider.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as SliderPrimitive from '@radix-ui/react-slider'
5 |
6 | import { cn } from '@/lib/utils'
7 |
8 | const Slider = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 |
21 |
22 |
23 |
24 |
25 | ))
26 | Slider.displayName = SliderPrimitive.Root.displayName
27 |
28 | export { Slider }
29 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/switch.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as SwitchPrimitives from '@radix-ui/react-switch'
5 |
6 | import { cn } from '@/lib/utils'
7 |
8 | const Switch = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 |
25 |
26 | ))
27 | Switch.displayName = SwitchPrimitives.Root.displayName
28 |
29 | export { Switch }
30 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | import { cn } from '@/lib/utils'
4 |
5 | export interface TextareaProps
6 | extends React.TextareaHTMLAttributes {}
7 |
8 | const Textarea = React.forwardRef(
9 | ({ className, ...props }, ref) => {
10 | return (
11 |
19 | )
20 | }
21 | )
22 | Textarea.displayName = 'Textarea'
23 |
24 | export { Textarea }
25 |
--------------------------------------------------------------------------------
/sweep_chat/components/ui/toaster.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import {
4 | Toast,
5 | ToastClose,
6 | ToastDescription,
7 | ToastProvider,
8 | ToastTitle,
9 | ToastViewport,
10 | } from '@/components/ui/toast'
11 | import { useToast } from '@/components/ui/use-toast'
12 |
13 | export function Toaster() {
14 | const { toasts } = useToast()
15 |
16 | return (
17 |
18 | {toasts.map(function ({ id, title, description, action, ...props }) {
19 | return (
20 |
21 |
22 | {title && {title}}
23 | {description && (
24 | {description}
25 | )}
26 |
27 | {action}
28 |
29 |
30 | )
31 | })}
32 |
33 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/sweep_chat/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress'
2 |
3 | export default defineConfig({
4 | e2e: {
5 | baseUrl: 'http://localhost:3000',
6 | setupNodeEvents(on: Cypress.PluginEvents, config: Cypress.Config) {
7 | // implement node event listeners here
8 | },
9 | viewportWidth: 1536,
10 | viewportHeight: 960,
11 | },
12 | })
13 |
--------------------------------------------------------------------------------
/sweep_chat/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
6 |
--------------------------------------------------------------------------------
/sweep_chat/cypress/support/e2e.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/e2e.ts is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/sweep_chat/instrumentation.ts:
--------------------------------------------------------------------------------
1 | export async function register() {
2 | if (process.env.NEXT_RUNTIME === 'nodejs') {
3 | await import('./sentry.server.config')
4 | }
5 |
6 | if (process.env.NEXT_RUNTIME === 'edge') {
7 | await import('./sentry.edge.config')
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/sweep_chat/lib/constants.ts:
--------------------------------------------------------------------------------
1 | import { javascript } from '@codemirror/lang-javascript'
2 | import { go } from '@codemirror/lang-go'
3 | import { python } from '@codemirror/lang-python'
4 | import { dracula } from 'react-syntax-highlighter/dist/cjs/styles/prism'
5 | import { Extension } from '@uiw/react-codemirror'
6 |
7 | const codeStyle = dracula
8 |
9 | const modelMap: Record = {
10 | 'claude-3-5-sonnet-20240620': 'Sonnet 3.5',
11 | 'claude-3-opus-20240229': 'Opus',
12 | 'claude-3-sonnet-20240229': 'Sonnet',
13 | 'claude-3-haiku-20240307': 'Haiku',
14 | 'gpt-4o': 'GPT-4o',
15 | }
16 |
17 | const roleToColor = {
18 | user: 'bg-zinc-600',
19 | assistant: 'bg-zinc-700',
20 | function: 'bg-zinc-800',
21 | }
22 |
23 | const typeNameToColor = {
24 | source: 'bg-blue-900',
25 | tests: 'bg-green-900',
26 | dependencies: 'bg-zinc-600',
27 | tools: 'bg-purple-900',
28 | docs: 'bg-yellow-900',
29 | }
30 |
31 | const languageMapping: Record = {
32 | js: javascript(),
33 | jsx: javascript({ jsx: true }),
34 | ts: javascript({ typescript: true }),
35 | tsx: javascript({ typescript: true, jsx: true }),
36 | go: go(),
37 | py: python(),
38 | }
39 |
40 | const DEFAULT_K: number = 8
41 | const DEFAULT_MODEL = 'claude-3-5-sonnet-20240620'
42 |
43 | export {
44 | codeStyle,
45 | modelMap,
46 | DEFAULT_K,
47 | DEFAULT_MODEL,
48 | roleToColor,
49 | typeNameToColor,
50 | languageMapping,
51 | }
52 |
--------------------------------------------------------------------------------
/sweep_chat/lib/contextManagers.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch, SetStateAction } from 'react'
2 |
3 | // Set isLoading to true, then set it to false on exit, always
4 | export const withLoading = async (
5 | setIsLoading: Dispatch>,
6 | callback: (() => void) | (() => Promise),
7 | onError: (error: Error) => void = () => {}
8 | ) => {
9 | setIsLoading(true)
10 | try {
11 | const result = callback()
12 | if (result instanceof Promise) {
13 | await result
14 | }
15 | } catch (error) {
16 | onError?.(error as Error)
17 | throw error
18 | } finally {
19 | setIsLoading(false)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/sweep_chat/lib/posthog.ts:
--------------------------------------------------------------------------------
1 | import posthog from 'posthog-js'
2 |
3 | if (typeof window !== 'undefined') {
4 | posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
5 | api_host: '/ingest',
6 | ui_host: 'https://us.posthog.com',
7 | })
8 | posthog.debug(false)
9 | }
10 |
11 | export { posthog }
12 |
--------------------------------------------------------------------------------
/sweep_chat/lib/pullUtils.ts:
--------------------------------------------------------------------------------
1 | import { PullRequest } from './types'
2 |
3 | const isPullRequestEqual = (pr1: PullRequest, pr2: PullRequest) => {
4 | return (
5 | pr1.number === pr2.number &&
6 | pr1.branch === pr2.branch &&
7 | pr1.repo_name === pr2.repo_name &&
8 | pr1.title === pr2.title
9 | )
10 | }
11 |
12 | export { isPullRequestEqual }
13 |
--------------------------------------------------------------------------------
/sweep_chat/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from 'clsx'
2 | import { twMerge } from 'tailwind-merge'
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/sweep_chat/next.config.mjs:
--------------------------------------------------------------------------------
1 | import {withSentryConfig} from '@sentry/nextjs';
2 | /** @type {import('next').NextConfig} */
3 | const nextConfig = {
4 | async rewrites() {
5 | return [
6 | {
7 | source: '/backend/:path*',
8 | destination: `${process.env.BACKEND_URL}/chat/backend/:path*` // should redirect at runtime instead: https://nextjs.org/docs/pages/building-your-application/routing/middleware
9 | },
10 | {
11 | source: "/ingest/static/:path*",
12 | destination: "https://us-assets.i.posthog.com/static/:path*",
13 | },
14 | {
15 | source: "/ingest/:path*",
16 | destination: "https://us.i.posthog.com/:path*",
17 | },
18 | ]
19 | },
20 | skipTrailingSlashRedirect: true,
21 | };
22 |
23 | export default withSentryConfig(nextConfig, {
24 |
25 | org: "sweep-ai",
26 | project: "sweep-chat",
27 |
28 | // Only print logs for uploading source maps in CI
29 | silent: !process.env.CI,
30 |
31 | // For all available options, see:
32 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
33 |
34 | // Upload a larger set of source maps for prettier stack traces (increases build time)
35 | widenClientFileUpload: true,
36 |
37 | // Transpiles SDK to be compatible with IE11 (increases bundle size)
38 | transpileClientSDK: true,
39 |
40 | // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
41 | // This can increase your server load as well as your hosting bill.
42 | // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
43 | // side errors will fail.
44 | tunnelRoute: "/monitoring",
45 |
46 | // Hides source maps from generated client bundles
47 | hideSourceMaps: true,
48 |
49 | // Automatically tree-shake Sentry logger statements to reduce bundle size
50 | disableLogger: true,
51 |
52 | // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
53 | // See the following for more information:
54 | // https://docs.sentry.io/product/crons/
55 | // https://vercel.com/docs/cron-jobs
56 | automaticVercelMonitors: true,
57 | });
--------------------------------------------------------------------------------
/sweep_chat/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('postcss-load-config').Config} */
2 | const config = {
3 | plugins: {
4 | tailwindcss: {},
5 | },
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/sweep_chat/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sweep_chat/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sweep_chat/sentry.client.config.ts:
--------------------------------------------------------------------------------
1 | // This file configures the initialization of Sentry on the client.
2 | // The config you add here will be used whenever a users loads a page in their browser.
3 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/
4 |
5 | import * as Sentry from '@sentry/nextjs'
6 |
7 | Sentry.init({
8 | dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
9 |
10 | // Adjust this value in production, or use tracesSampler for greater control
11 | tracesSampleRate: 1,
12 |
13 | // Setting this option to true will print useful information to the console while you're setting up Sentry.
14 | debug: false,
15 |
16 | replaysOnErrorSampleRate: 1.0,
17 |
18 | // This sets the sample rate to be 10%. You may want this to be 100% while
19 | // in development and sample at a lower rate in production
20 | replaysSessionSampleRate: 0.1,
21 |
22 | // You can remove this option if you're not planning to use the Sentry Session Replay feature:
23 | integrations: [
24 | Sentry.replayIntegration({
25 | // Additional Replay configuration goes in here, for example:
26 | maskAllText: true,
27 | blockAllMedia: true,
28 | }),
29 | ],
30 | })
31 |
--------------------------------------------------------------------------------
/sweep_chat/sentry.edge.config.ts:
--------------------------------------------------------------------------------
1 | // This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).
2 | // The config you add here will be used whenever one of the edge features is loaded.
3 | // Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.
4 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/
5 |
6 | import * as Sentry from '@sentry/nextjs'
7 |
8 | Sentry.init({
9 | dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
10 |
11 | // Adjust this value in production, or use tracesSampler for greater control
12 | tracesSampleRate: 1,
13 |
14 | // Setting this option to true will print useful information to the console while you're setting up Sentry.
15 | debug: false,
16 | })
17 |
--------------------------------------------------------------------------------
/sweep_chat/sentry.server.config.ts:
--------------------------------------------------------------------------------
1 | // This file configures the initialization of Sentry on the server.
2 | // The config you add here will be used whenever the server handles a request.
3 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/
4 |
5 | import * as Sentry from '@sentry/nextjs'
6 |
7 | Sentry.init({
8 | dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
9 |
10 | // Adjust this value in production, or use tracesSampler for greater control
11 | tracesSampleRate: 1,
12 |
13 | // Setting this option to true will print useful information to the console while you're setting up Sentry.
14 | debug: false,
15 |
16 | // Uncomment the line below to enable Spotlight (https://spotlightjs.com)
17 | // spotlight: process.env.NODE_ENV === 'development',
18 | })
19 |
--------------------------------------------------------------------------------
/sweep_chat/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "plugins": [
16 | {
17 | "name": "next"
18 | }
19 | ],
20 | "paths": {
21 | "@/*": ["./*"]
22 | },
23 | "baseUrl": "."
24 | },
25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 | "exclude": ["node_modules"],
27 | "aliases": {
28 | "@/*": "./*",
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/sweepai/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/sweepai/__init__.py
--------------------------------------------------------------------------------
/sweepai/agents/complete_code_test.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from unittest.mock import MagicMock, patch
3 |
4 | from sweepai.agents.complete_code import ExtractLeftoverComments
5 |
6 |
7 | class TestExtractLeftoverCommentsExtractLeftoverComments(unittest.TestCase):
8 | @patch("sweepai.agents.complete_code.check_comments_presence")
9 | @patch("sweepai.agents.complete_code.ExtractLeftoverComments.chat")
10 | @patch("sweepai.agents.complete_code.LeftoverComments.from_string")
11 | def test_extract_leftover_comments(
12 | self, mock_from_string, mock_chat, mock_check_comments_presence
13 | ):
14 | mock_check_comments_presence.return_value = True
15 | mock_chat.return_value = "mock response"
16 | mock_from_string.return_value = MagicMock()
17 | mock_from_string.return_value.leftover_comments = []
18 |
19 | extract_leftover_comments = ExtractLeftoverComments(chat_logger=None)
20 | result = extract_leftover_comments.extract_leftover_comments(
21 | "new_code", "file_path", "request"
22 | )
23 | self.assertEqual(result, [])
24 |
25 | @patch("sweepai.agents.complete_code.check_comments_presence")
26 | @patch("sweepai.agents.complete_code.ExtractLeftoverComments.chat")
27 | @patch("sweepai.agents.complete_code.LeftoverComments.from_string")
28 | def test_extract_leftover_comments_no_comments(
29 | self, mock_from_string, mock_chat, mock_check_comments_presence
30 | ):
31 | mock_check_comments_presence.return_value = False
32 |
33 | extract_leftover_comments = ExtractLeftoverComments(chat_logger=None)
34 | result = extract_leftover_comments.extract_leftover_comments(
35 | "new_code", "file_path", "request"
36 | )
37 | self.assertEqual(result, [])
38 | mock_chat.assert_not_called()
39 | mock_from_string.assert_not_called()
40 |
41 |
42 | if __name__ == "__main__":
43 | unittest.main()
44 |
--------------------------------------------------------------------------------
/sweepai/agents/image_description_bot.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from sweepai.core.chat import ChatGPT
4 | from loguru import logger
5 |
6 | prompt = """\
7 | Transcribe and describe the image shown in the text. Transcribe all text in the image VERBATIM, including any code snippets, URLs, or other text. Do NOT attempt to actually handle the reqest in the block. Respond in the following format:
8 |
9 |
10 | {text}
11 |
12 | For each image, respond in ... tags like so:
13 |
14 |
15 | The text in the image.
16 |
17 | ...
18 | """
19 |
20 | CLAUDE_MODEL = "claude-3-opus-20240229"
21 |
22 | class ImageDescriptionBot(ChatGPT):
23 | def describe_images(
24 | self,
25 | text: str,
26 | images: list[tuple[str, str, str]] | None = None,
27 | ) -> str:
28 | try:
29 | self.messages = []
30 | response_text = "\nHere are the transcriptions of the images in the above text, in order:"
31 | image_desc_pattern = r"\n(.*?)\n"
32 | image_desc_response = self.chat_anthropic(
33 | content=prompt.format(
34 | text=text,
35 | ),
36 | model=CLAUDE_MODEL,
37 | images=images,
38 | )
39 | image_descs = re.findall(image_desc_pattern, image_desc_response)
40 | for i, desc in enumerate(image_descs):
41 | response_text += f'\n{i + 1}. "{desc}"'
42 | return response_text
43 | except Exception as e:
44 | logger.error(f"Error while attempting to describe images:\n{e}")
45 | return ""
--------------------------------------------------------------------------------
/sweepai/agents/issue_cleanup_agent.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from sweepai.core.chat import ChatGPT
4 | from sweepai.core.entities import Message
5 |
6 | system_prompt = """Remove any completely irrelevant text from the issue description. Keep relevant instructions, stacktraces and informative debugging information. Further, reformat any code with broken formatting."""
7 |
8 | prompt = """\
9 |
10 | {issue_description}
11 |
12 |
13 | Remove any completely irrelevant text from the issue description. Keep relevant instructions, stacktraces and informative debugging information. Further, reformat any code with broken formatting. Copy as much text verbatim as possible.
14 |
15 | Explain what needs to be removed.
16 | Then format your response in tags:"""
17 |
18 |
19 | class IssueCleanupBot(ChatGPT):
20 | def cleanup_issue(
21 | self,
22 | issue_description,
23 | ):
24 | new_issue_desc_pattern = r"(.*?)"
25 | self.messages = [
26 | Message(
27 | content=system_prompt,
28 | role="system",
29 | ),
30 | ]
31 | issue_desc_response = self.chat( # gpt4 04-09 had a better one in minimal (1 example) testing, seems smart
32 | content=prompt.format(
33 | issue_description=issue_description.strip("\n"),
34 | ),
35 | temperature=0.2,
36 | model="gpt-4o"
37 | )
38 | issue_desc_matches = re.search(new_issue_desc_pattern, issue_desc_response, re.DOTALL)
39 | if not issue_desc_matches or not issue_desc_matches.group(1).strip():
40 | return issue_description
41 | issue_desc = issue_desc_matches.group(1)
42 | issue_desc = issue_desc.strip()
43 | return issue_desc
44 |
--------------------------------------------------------------------------------
/sweepai/agents/pr_description_bot.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from sweepai.core.chat import ChatGPT
4 |
5 | prompt = """\
6 | Write a pull request description that reflects all changes in this pull request. Here are the changes:
7 |
8 | {diffs}
9 |
10 |
11 | Here is the pull request title:
12 |
13 | {pr_title}
14 |
15 |
16 | Format your response using the following XML tags:
17 |
18 | # Description
19 | Short description of the pull request.
20 | # Summary
21 | Concise bulleted description of the pull request. Markdown format `variables`, `files`, and `directories` like this.
22 | """
23 |
24 | CLAUDE_MODEL = "claude-3-haiku-20240307"
25 |
26 | class PRDescriptionBot(ChatGPT):
27 | def describe_diffs(
28 | self,
29 | diffs,
30 | pr_title,
31 | ):
32 | self.messages = []
33 | # attempt to generate description 3 times
34 | pr_desc_pattern = r"\n(.*?)\n"
35 | for attempt in [0, 1, 2]:
36 | pr_desc_response = self.chat_anthropic(
37 | content=prompt.format(
38 | diffs=diffs,
39 | pr_title=pr_title,
40 | ),
41 | model=CLAUDE_MODEL,
42 | )
43 | pr_desc_matches = re.search(pr_desc_pattern, pr_desc_response, re.DOTALL)
44 | if pr_desc_matches is None:
45 | if attempt == 2:
46 | return ""
47 | else:
48 | break
49 |
50 | pr_desc = pr_desc_matches.group(1)
51 | pr_desc = pr_desc.strip()
52 | return pr_desc
53 |
54 | if __name__ == "__main__":
55 | bot = PRDescriptionBot()
56 | diffs = """\
57 | - `variables` changed in `files`
58 | - `variables` changed in `directories`
59 | - `variables` changed in `files`
60 | - `variables` changed in `directories`
61 | + `variables` added in `files`
62 | + `variables` added in `directories`
63 | """
64 | pr_title = "PR Title"
65 | pr_desc = bot.describe_diffs(diffs, pr_title)
66 | print(pr_desc)
--------------------------------------------------------------------------------
/sweepai/agents/rg_extractor.py:
--------------------------------------------------------------------------------
1 | from sweepai.core.chat import call_llm
2 | from sweepai.utils.str_utils import extract_xml_tag
3 |
4 |
5 | instructions = """I'm going to give you a GitHub issue. Please carefully read the issue description and identify any specific entities mentioned that are critical to the issue that I must find all occurrences of. This should be an uncommon term in the relevant files. Give me a brief set of at most 5 entity names that you should grep for in the provided files, prioritizing the ones directly related to the specific entities mentioned in the issue, and those that are uncommon in this codebase. Grepping these entity names should be helpful with finding the right places to make changes.
6 |
7 | Respond in this format:
8 |
9 |
10 | Lists of new line separated entities.
11 | """
12 |
13 | def get_list_of_entities(
14 | message: str,
15 | ):
16 | response = call_llm(
17 | system_prompt=instructions,
18 | user_prompt=message + "\n\n" + instructions,
19 | use_openai=True,
20 | )
21 | entities = extract_xml_tag(response, "entities")
22 | return [entity.strip() for entity in entities.split("\n")]
23 |
--------------------------------------------------------------------------------
/sweepai/agents/summarize_file.py:
--------------------------------------------------------------------------------
1 | from sweepai.core.chat import call_llm
2 | from sweepai.logn.cache import file_cache
3 | from sweepai.utils.github_utils import MockClonedRepo
4 |
5 | instructions = "Explain in great detail what types of content this directory contains (code, documentation, configs, assets, tests etc.). Explain the purpose of the directory. Be concise and optimize for informational density. One paragraph."
6 |
7 | system_prompt = "Your job is to summarize the following file from the repository. " + instructions
8 |
9 | user_prompt = """Summarize the following file from the repository.
10 |
11 |
12 | {repo_name}
13 |
14 |
15 |
16 | {file_path}
17 |
18 |
19 |
20 | {file_contents}
21 |
22 |
23 | """ + instructions
24 |
25 | @file_cache()
26 | def summarize_file(file_path: str, file_contents: str, repo_name: str):
27 | response = call_llm(
28 | system_prompt,
29 | user_prompt,
30 | params={
31 | "repo_name": repo_name,
32 | "file_path": file_path,
33 | "file_contents": file_contents,
34 | },
35 | # verbose=False
36 | )
37 |
38 | return response
39 |
40 | if __name__ == "__main__":
41 | cloned_repo = MockClonedRepo("/tmp/sweep", "sweepai/sweep")
42 | summarize_file("sweepai/handlers/on_ticket.py", cloned_repo)
43 |
--------------------------------------------------------------------------------
/sweepai/cli_test.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import unittest
4 | from unittest.mock import mock_open, patch
5 |
6 | from sweepai.cli import load_config, run
7 |
8 |
9 | class TestConfigLoading(unittest.TestCase):
10 | @patch.dict(os.environ, {}, clear=True)
11 | @patch("os.path.exists", return_value=True)
12 | @patch(
13 | "builtins.open",
14 | new_callable=mock_open,
15 | read_data=json.dumps(
16 | {"GITHUB_PAT": "test_github_pat", "OPENAI_API_KEY": "test_openai_key"}
17 | ),
18 | )
19 | def test_load_config(self, mock_file, mock_exists):
20 | with self.assertRaises(KeyError):
21 | os.environ["GITHUB_PAT"]
22 | with self.assertRaises(KeyError):
23 | os.environ["OPENAI_API_KEY"]
24 | load_config()
25 | self.assertEqual(os.environ["GITHUB_PAT"], "test_github_pat")
26 | self.assertEqual(os.environ["OPENAI_API_KEY"], "test_openai_key")
27 |
28 |
29 | class TestCLIRunIsssue(unittest.TestCase):
30 | @patch("os.path.exists", return_value=False)
31 | def test_run_issue_no_config(self, mock_exists):
32 | with self.assertRaises(ValueError):
33 | run("https://github.com/sweepai/e2e/issues/1")
34 |
35 |
36 | if __name__ == "__main__":
37 | unittest.main()
38 |
--------------------------------------------------------------------------------
/sweepai/config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/sweepai/config/__init__.py
--------------------------------------------------------------------------------
/sweepai/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/sweepai/core/__init__.py
--------------------------------------------------------------------------------
/sweepai/core/external_searcher.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from sweepai.core.chat import ChatGPT
4 | from sweepai.core.entities import Message
5 | from sweepai.core.prompts import external_search_prompt, external_search_system_prompt
6 | from loguru import logger
7 | from sweepai.utils.html_extractor import extract_info
8 |
9 |
10 | class ExternalSearcher(ChatGPT):
11 | @staticmethod
12 | def extract_links(content: str) -> list[str]:
13 | pattern = r"\b(?:(?:https?|ftp)://|www\.)\S+\b"
14 | return list(set(re.findall(pattern, content)))
15 |
16 | def extract_summary_from_link(self, url: str, problem: str) -> str:
17 | page_metadata = extract_info(url)
18 |
19 | self.messages = [Message(role="system", content=external_search_system_prompt)]
20 | response = self.chat(
21 | external_search_prompt.format(
22 | page_metadata=page_metadata,
23 | problem=problem,
24 | )
25 | )
26 |
27 | return response.strip() + "\n"
28 |
29 | @staticmethod
30 | def extract_summaries(content: str):
31 | logger.info("Extracting summaries from content")
32 | links = ExternalSearcher.extract_links(content)
33 | if not links:
34 | return ""
35 | result = "\n\n**Summaries of links found in the content:**\n\n"
36 | for link in links:
37 | logger.info(f"Extracting summary from {link}")
38 | try:
39 | external_searcher = ExternalSearcher()
40 | summary = external_searcher.extract_summary_from_link(link, content)
41 | result += f"{link}:\n\n{summary}\n\n"
42 | except Exception as e:
43 | logger.error(f"External search error: {e}")
44 | return result
45 |
--------------------------------------------------------------------------------
/sweepai/core/snippet_utils.py:
--------------------------------------------------------------------------------
1 | def convert_lines_to_and_merge_ranges(
2 | lines: list[int],
3 | range_size: int = 10,
4 | lower_bound: int = -1,
5 | upper_bound: int = -1,
6 | offset: int = 0, # offset to apply to each line number
7 | ) -> list[tuple[int, int]]:
8 | """
9 | Converts a list of line numbers to a list of ranges, handles merging of ranges with custom range_size
10 | """
11 | if not lines:
12 | return []
13 | ranges = []
14 | lines.sort()
15 | range_size = max(0, range_size) # ensure at least one line is present
16 | for line in lines:
17 | if offset:
18 | line += offset
19 | start = max(0, line - range_size)
20 | end = line + range_size
21 | if lower_bound != -1:
22 | start = max(start, lower_bound)
23 | if upper_bound != -1:
24 | end = min(end, upper_bound)
25 | if not ranges:
26 | ranges.append((start, end))
27 | else:
28 | # check if we need to merge the ranges
29 | previous_start, previous_end = ranges[-1]
30 | if start <= previous_end:
31 | ranges[-1] = (previous_start, end)
32 | else:
33 | ranges.append((start, end))
34 | return ranges
35 |
36 |
37 | def merge_snippet_ranges(ranges: list[tuple[int, int]]) -> list[tuple[int, int]]:
38 | """
39 | Merges overlapping ranges
40 | """
41 | if not ranges:
42 | return []
43 | ranges.sort()
44 | merged_ranges = [ranges[0]]
45 | for current_start, current_end in ranges[1:]:
46 | previous_start, previous_end = merged_ranges[-1]
47 | if current_start <= previous_end:
48 | merged_ranges[-1] = (previous_start, max(previous_end, current_end))
49 | else:
50 | merged_ranges.append((current_start, current_end))
51 | return merged_ranges
--------------------------------------------------------------------------------
/sweepai/dataclasses/check_status.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Literal, TypedDict
2 |
3 | class CheckStatus(TypedDict):
4 | message: str
5 | stdout: str
6 | succeeded: Optional[bool]
7 | status: Literal["pending", "running", "success", "failure", "cancelled"]
8 | llm_message: str
9 | container_name: str
10 |
11 | # Status can be one of: completed, action_required, cancelled, failure, neutral, skipped, stale, success, timed_out, in_progress, queued, requested, waiting, pending.
12 | gha_to_check_status = {
13 | "completed": "success",
14 | "action_required": "success",
15 | "cancelled": "cancelled",
16 | "failure": "failure",
17 | "neutral": "success",
18 | "skipped": "success",
19 | "stale": "success",
20 | "success": "success",
21 | "timed_out": "failure",
22 | "in_progress": "running",
23 | "queued": "pending",
24 | "requested": "pending",
25 | "waiting": "pending",
26 | "pending": "pending",
27 | }
28 |
29 | gha_to_succeeded = {
30 | "completed": True,
31 | "action_required": False,
32 | "cancelled": False,
33 | "failure": False,
34 | "neutral": True,
35 | "skipped": True,
36 | "stale": True,
37 | "success": True,
38 | }
39 |
40 | gha_to_message = {
41 | "completed": "Github Action completed",
42 | "action_required": "Github Action action required",
43 | "cancelled": "Github Action cancelled",
44 | "failure": "Github Action failed",
45 | "neutral": "Github Action neutral",
46 | "skipped": "Github Action skipped",
47 | "stale": "Github Action stale",
48 | "success": "Github Action succeeded",
49 | "timed_out": "Github Action timed out",
50 | "in_progress": "Github Action in progress",
51 | "queued": "Github Action queued",
52 | "requested": "Github Action requested",
53 | "waiting": "Github Action waiting",
54 | "pending": "Github Action pending",
55 | }
56 |
--------------------------------------------------------------------------------
/sweepai/dataclasses/code_suggestions.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import Literal, Optional
3 |
4 |
5 | @dataclass
6 | class CodeSuggestion:
7 | file_path: str
8 | original_code: str
9 | new_code: str
10 | file_contents: str = ""
11 |
12 | @dataclass
13 | class StatefulCodeSuggestion(CodeSuggestion):
14 | state: Literal["pending", "processing", "done", "error"] = "pending"
15 | error: Optional[str] = None
16 |
17 |
--------------------------------------------------------------------------------
/sweepai/dataclasses/comments.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 |
3 |
4 | @dataclass
5 | class CommentDiffSpan:
6 | old_start_line: int
7 | old_end_line: int
8 | new_start_line: int
9 | new_end_line: int
10 | new_code: str
11 | file_name: str
--------------------------------------------------------------------------------
/sweepai/dataclasses/dockerfile_config.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | import json
3 |
4 |
5 | @dataclass
6 | class DockerfileConfig:
7 | dockerfile_path: str
8 | image_name: str # not sure if both are needed, but the intention is to clean up the image after the container is done
9 | container_name: str
10 | command: str
11 |
12 | def load_dockerfile_configs_from_path(location) -> DockerfileConfig:
13 | # load an instance of this from a json file
14 | with open(location, 'r') as f:
15 | data = json.load(f)
16 | return [DockerfileConfig(**item) for item in data]
--------------------------------------------------------------------------------
/sweepai/dataclasses/files.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 |
3 |
4 | @dataclass
5 | class Document:
6 | title: str
7 | content: str
--------------------------------------------------------------------------------
/sweepai/dataclasses/gha_fix.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import Literal
3 |
4 |
5 |
6 | @dataclass
7 | class GHAFix:
8 | suite_url: str
9 | logs: str = ""
10 | status: Literal["pending"] | Literal["skipped"] | Literal["planning"] | Literal["modifying"] | Literal["done"] = "pending"
11 | # starts with pending, skip if suite passes
12 | # if it errors we first plan changes and then mark as done
13 | fix_commit_hash: str = ""
14 | fix_diff: str = ""
15 |
16 | @property
17 | def repo_full_name(self):
18 | return self.suite_url.split("/")[3:5]
19 |
20 | def to_markdown(self):
21 | if self.status == "done":
22 | return f"I resolved the [GitHub Actions errors]({self.suite_url}) at with commit https://github.com/{self.repo_full_name}/commit/{self.fix_commit_hash}. Here were my changes:\n\n{self.fix_diff}"
23 | elif self.status == "modifying":
24 | return f"I'm currently resolving the [GitHub Actions errors]({self.suite_url}). Here are my plans:\n\n{self.fix_diff}"
25 | elif self.status == "planning":
26 | return f"The GitHub Actions have failed. You can view the logs [here]({self.suite_url}). I'm planning currently trying to fix the errors."
27 | elif self.status == "skipped":
28 | return f"The GitHub Actions have completed successfully. You can view the logs [here]({self.suite_url})."
29 | elif self.status == "pending":
30 | return "I'm currently waiting for the GitHub Actions to complete running, so that I can address any errors."
--------------------------------------------------------------------------------
/sweepai/dataclasses/searchindex.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 |
3 |
4 | @dataclass
5 | class SearchIndex:
6 | file_list: list[str]
--------------------------------------------------------------------------------
/sweepai/dataclasses/separatedsnippets.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass, field
2 | from typing import Iterator, Tuple
3 | from sweepai.core.entities import Snippet
4 |
5 | @dataclass
6 | class SeparatedSnippets:
7 | tools: list[Snippet] = field(default_factory=list)
8 | junk: list[Snippet] = field(default_factory=list)
9 | dependencies: list[Snippet] = field(default_factory=list)
10 | docs: list[Snippet] = field(default_factory=list)
11 | tests: list[Snippet] = field(default_factory=list)
12 | source: list[Snippet] = field(default_factory=list)
13 |
14 | def add_snippet(self, snippet: Snippet, type_name: str):
15 | if type_name == "tools":
16 | self.tools.append(snippet)
17 | elif type_name == "junk":
18 | self.junk.append(snippet)
19 | elif type_name == "dependencies":
20 | self.dependencies.append(snippet)
21 | elif type_name == "docs":
22 | self.docs.append(snippet)
23 | elif type_name == "tests":
24 | self.tests.append(snippet)
25 | elif type_name == "source":
26 | self.source.append(snippet)
27 | else:
28 | raise ValueError(f"Unknown type_name: {type_name}")
29 |
30 | def override_list(self, attribute_name: str, new_list: list[Snippet]):
31 | if hasattr(self, attribute_name):
32 | setattr(self, attribute_name, new_list)
33 | else:
34 | raise AttributeError(f"List type '{attribute_name}' does not exist in SeparatedSnippets")
35 |
36 | def __iter__(self) -> Iterator[Tuple[str, list[Snippet]]]:
37 | yield "source", self.source
38 | yield "tests", self.tests
39 | yield "tools", self.tools
40 | yield "dependencies", self.dependencies
41 | yield "docs", self.docs
42 | # yield "junk", self.junk
43 | # we won't yield junk
--------------------------------------------------------------------------------
/sweepai/global_threads.py:
--------------------------------------------------------------------------------
1 | global_threads = []
--------------------------------------------------------------------------------
/sweepai/handlers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/sweepai/handlers/__init__.py
--------------------------------------------------------------------------------
/sweepai/handlers/on_button_click_test.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import Mock, patch
2 |
3 | from sweepai.handlers.on_button_click import handle_button_click
4 |
5 |
6 | def test_handle_button_click():
7 | mock_request_dict = {
8 | "installation": {"id": 1},
9 | "comment": {"body": "test body"},
10 | "repository": {"full_name": "test/repo"},
11 | "issue": {"number": 1},
12 | }
13 |
14 | with patch(
15 | "sweepai.handlers.on_button_click.get_github_client"
16 | ) as mock_get_github_client:
17 | mock_get_github_client.return_value = ("token", Mock())
18 | handle_button_click(mock_request_dict)
19 |
20 |
21 | def test_handle_button_click_revert_files():
22 | mock_request_dict = {
23 | "installation": {"id": 1},
24 | "comment": {"body": "test body"},
25 | "repository": {"full_name": "test/repo"},
26 | "issue": {"number": 1},
27 | "changes": {"title": "REVERT_CHANGED_FILES_TITLE"},
28 | }
29 |
30 | with patch(
31 | "sweepai.handlers.on_button_click.get_github_client"
32 | ) as mock_get_github_client:
33 | mock_get_github_client.return_value = ("token", Mock())
34 | handle_button_click(mock_request_dict)
35 |
36 |
37 | def test_handle_button_click_rules():
38 | mock_request_dict = {
39 | "installation": {"id": 1},
40 | "comment": {"body": "test body"},
41 | "repository": {"full_name": "test/repo"},
42 | "issue": {"number": 1},
43 | "changes": {"title": "RULES_TITLE"},
44 | }
45 |
46 | with patch(
47 | "sweepai.handlers.on_button_click.get_github_client"
48 | ) as mock_get_github_client:
49 | mock_get_github_client.return_value = ("token", Mock())
50 | handle_button_click(mock_request_dict)
51 |
--------------------------------------------------------------------------------
/sweepai/handlers/on_merge.py:
--------------------------------------------------------------------------------
1 | """
2 | This file contains the on_merge handler which is called when a pull request is merged to master.
3 | on_merge is called by sweepai/api.py
4 | """
5 |
6 | from loguru import logger
7 |
8 | # change threshold for number of lines changed
9 | CHANGE_BOUNDS = (10, 1500)
10 |
11 | # dictionary to map from github repo to the last time a rule was activated
12 | merge_rule_debounce = {}
13 |
14 | # debounce time in seconds
15 | DEBOUNCE_TIME = 120
16 |
17 | diff_section_prompt = """
18 |
19 | {diffs}
20 | """
21 |
22 |
23 | def comparison_to_diff(comparison, blocked_dirs):
24 | pr_diffs = []
25 | for file in comparison.files:
26 | diff = file.patch
27 | if (
28 | file.status == "added"
29 | or file.status == "modified"
30 | or file.status == "removed"
31 | ):
32 | if any(file.filename.startswith(dir) for dir in blocked_dirs):
33 | continue
34 | pr_diffs.append((file.filename, diff))
35 | else:
36 | logger.info(
37 | f"File status {file.status} not recognized"
38 | ) # TODO(sweep): We don't handle renamed files
39 | formatted_diffs = []
40 | for file_name, file_patch in pr_diffs:
41 | format_diff = diff_section_prompt.format(
42 | diff_file_path=file_name, diffs=file_patch
43 | )
44 | formatted_diffs.append(format_diff)
45 | return "\n".join(formatted_diffs)
46 |
--------------------------------------------------------------------------------
/sweepai/logn/README.md:
--------------------------------------------------------------------------------
1 | # logn
2 |
3 | "logn" is a tool for logging and visualizing the outputs of multiple threads and processes. This is especially helpful for FastAPI servers.
4 |
--------------------------------------------------------------------------------
/sweepai/logn/__init__.py:
--------------------------------------------------------------------------------
1 | from .cache import file_cache # noqa: F401
2 |
--------------------------------------------------------------------------------
/sweepai/logn/trace_util.py:
--------------------------------------------------------------------------------
1 | import linecache
2 | import sys
3 |
4 |
5 | def trace_lines(frame, event, arg):
6 | if event == "line":
7 | filename = frame.f_code.co_filename
8 | if "" in filename:
9 | lineno = frame.f_lineno
10 | line = linecache.getline(filename, lineno)
11 | print(f"Executing {filename}:line {lineno}:{line.rstrip()}")
12 | return trace_lines
13 |
14 |
15 | sys.settrace(trace_lines)
16 |
--------------------------------------------------------------------------------
/sweepai/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/sweepai/utils/__init__.py
--------------------------------------------------------------------------------
/sweepai/utils/buttons_test.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import unittest.mock
3 |
4 | from sweepai.utils.buttons import (
5 | Button,
6 | ButtonList,
7 | check_button_activated,
8 | check_button_title_match,
9 | create_action_buttons,
10 | create_button,
11 | get_toggled_state,
12 | )
13 |
14 |
15 | class TestButtons(unittest.TestCase):
16 | def test_create_button(self):
17 | self.assertEqual(create_button("Test", False), "- [ ] Test")
18 | self.assertEqual(create_button("Test", True), "- [x] Test")
19 |
20 | def test_create_action_buttons(self):
21 | labels = ["Test1", "Test2"]
22 | expected_output = "## Actions\n- [ ] Test1\n- [ ] Test2"
23 | self.assertEqual(create_action_buttons(labels), expected_output)
24 |
25 | def test_get_toggled_state(self):
26 | changes_request = unittest.mock.Mock()
27 | changes_request.body_from = "- [x] Test"
28 | self.assertTrue(get_toggled_state("Test", changes_request))
29 |
30 | def test_check_button_activated(self):
31 | changes_request = unittest.mock.Mock()
32 | changes_request.body_from = "- [ ] Test"
33 | self.assertTrue(check_button_activated("Test", "- [x] Test", changes_request))
34 |
35 | def test_check_button_title_match(self):
36 | changes_request = unittest.mock.Mock()
37 | changes_request.body_from = "Test"
38 | self.assertTrue(check_button_title_match("Test", "Test", changes_request))
39 |
40 | def test_button(self):
41 | button = Button("Test", True)
42 | self.assertEqual(str(button), "- [x] Test")
43 |
44 | def test_button_list(self):
45 | buttons = [Button("Test1", False), Button("Test2", True)]
46 | button_list = ButtonList("## My Buttons", buttons)
47 | self.assertEqual(
48 | button_list.serialize(), "## My Buttons\n- [ ] Test1\n- [x] Test2"
49 | )
50 | self.assertEqual(button_list.get_clicked_buttons(), [buttons[1]])
51 |
52 |
53 | if __name__ == "__main__":
54 | unittest.main()
55 |
--------------------------------------------------------------------------------
/sweepai/utils/code_tree_test.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | from sweepai.utils.code_tree import CodeTree
4 |
5 |
6 | class TestCodeTree(unittest.TestCase):
7 | def test_get_lines_surrounding(self):
8 | code = """import math
9 |
10 | def square_root(x):
11 | if x < 0:
12 | raise ValueError("Negative value")
13 | print(
14 | "hello world"
15 | )
16 | return math.sqrt(x)
17 |
18 | print(square_root(4))
19 | """
20 | tree = CodeTree.from_code(code)
21 |
22 | # Line inside the 'import' statement
23 | result = tree.get_lines_surrounding(0)
24 | expected = (0, 0)
25 | self.assertEqual(result, expected)
26 |
27 | # Line not present
28 | result = tree.get_lines_surrounding(100)
29 | self.assertEqual(result, (100, 100))
30 |
31 |
32 | if __name__ == "__main__":
33 | unittest.main()
34 |
--------------------------------------------------------------------------------
/sweepai/utils/comment_utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 |
4 |
5 | def check_comments_presence(file_path: str, new_code: str) -> bool:
6 | _, file_extension = os.path.splitext(file_path)
7 | comment_patterns = {
8 | ".py": "#",
9 | ".js": "//",
10 | ".ts": "//",
11 | ".jsx": "//",
12 | ".tsx": "//",
13 | ".java": "//",
14 | ".c": "/*",
15 | ".cpp": "//",
16 | ".cs": "//",
17 | ".php": "//",
18 | ".swift": "//",
19 | ".rb": "#",
20 | }
21 | if file_extension not in comment_patterns:
22 | return False
23 | comment_pattern = comment_patterns.get(file_extension, "")
24 | return bool(re.search(comment_pattern, new_code))
25 |
--------------------------------------------------------------------------------
/sweepai/utils/comment_utils_test.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | from sweepai.utils.comment_utils import check_comments_presence
4 |
5 |
6 | class TestCommentUtils(unittest.TestCase):
7 | def test_check_comments_presence(self):
8 | # Test Python file with a comment
9 | self.assertEqual(
10 | check_comments_presence("test.py", "# This is a comment"), True
11 | )
12 |
13 | # Test Python file without a comment
14 | self.assertEqual(
15 | check_comments_presence("test.py", 'print("Hello, World!")'), False
16 | )
17 |
18 | # Test JavaScript file with a comment
19 | self.assertEqual(
20 | check_comments_presence("test.js", "// This is a comment"), True
21 | )
22 |
23 | # Test JavaScript file without a comment
24 | self.assertEqual(
25 | check_comments_presence("test.js", 'console.log("Hello, World!");'), False
26 | )
27 |
28 | # Test unsupported file type with a comment
29 | self.assertEqual(
30 | check_comments_presence("test.txt", "# This is a comment"), False
31 | )
32 |
33 | # Test unsupported file type without a comment
34 | self.assertEqual(check_comments_presence("test.txt", "Hello, World!"), False)
35 |
36 |
37 | if __name__ == "__main__":
38 | unittest.main()
39 |
--------------------------------------------------------------------------------
/sweepai/utils/concurrency_utils.py:
--------------------------------------------------------------------------------
1 | def fire_and_forget_wrapper(call):
2 | """
3 | This decorator is used to run a function in a separate thread.
4 | It does not return anything and does not wait for the function to finish.
5 | It fails silently.
6 | """
7 |
8 | def wrapper(*args, **kwargs):
9 | try:
10 | return call(*args, **kwargs)
11 | except Exception:
12 | pass
13 |
14 | return wrapper
--------------------------------------------------------------------------------
/sweepai/utils/docker_utils.py:
--------------------------------------------------------------------------------
1 | import urllib
2 | from datetime import datetime, timedelta, timezone
3 |
4 | import requests
5 |
6 |
7 | def get_latest_docker_version():
8 | def humanize_time(delta):
9 | seconds = delta.total_seconds()
10 | minutes, seconds = divmod(seconds, 60)
11 | hours, minutes = divmod(minutes, 60)
12 | days, hours = divmod(hours, 24)
13 | if days > 0:
14 | return f"{int(days)} days ago"
15 | elif hours > 0:
16 | return f"{int(hours)} hours ago"
17 | elif minutes > 0:
18 | return f"{int(minutes)} minutes ago"
19 | else:
20 | return "just now"
21 |
22 | url = "https://hub.docker.com/v2/namespaces/sweepai/repositories/sweep/tags"
23 | try:
24 | response = requests.get(url, timeout=(1, 1))
25 | response.raise_for_status() # Raises HTTPError for bad responses (4xx and 5xx)
26 | data = response.json()
27 | truncated_time = data["results"][0]["last_updated"].split(".")[0]
28 | last_updated = datetime.fromisoformat(f"{truncated_time}+00:00")
29 | except Exception:
30 | # subtract 6 hours
31 | last_updated = datetime.now(timezone.utc) - timedelta(hours=6)
32 | # Truncate fractional seconds
33 | duration_since_last_update = datetime.now(timezone.utc) - last_updated
34 | return humanize_time(duration_since_last_update)
35 |
36 |
37 | def get_docker_badge():
38 | try:
39 | docker_update_duration = get_latest_docker_version()
40 | encoded_duration = urllib.parse.quote(docker_update_duration)
41 | badge_url = f"https://img.shields.io/badge/Docker%20Version%20Updated-{encoded_duration}-blue"
42 | markdown_badge = f"
"
43 | return markdown_badge
44 | except Exception:
45 | return ""
46 |
--------------------------------------------------------------------------------
/sweepai/utils/docker_utils_test.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | from sweepai.utils.docker_utils import get_latest_docker_version
4 |
5 |
6 | class TestDockerUtils(unittest.TestCase):
7 | def test_get_latest_docker_version(self):
8 | result = get_latest_docker_version()
9 | self.assertIsInstance(result, str)
10 | self.assertRegex(result, r"\d+ (days|hours|minutes|seconds) ago|just now")
11 |
12 |
13 | if __name__ == "__main__":
14 | unittest.main()
15 |
--------------------------------------------------------------------------------
/sweepai/utils/hash.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import hmac
3 |
4 | from sweepai.config.server import WEBHOOK_SECRET
5 |
6 |
7 | def hash_sha256(text: str):
8 | return hashlib.sha256(text.encode("utf-8", "ignore")).hexdigest()
9 |
10 | def verify_signature(
11 | payload_body: bytes,
12 | signature_header: str | None
13 | ):
14 | """Verify that the payload was sent from GitHub by validating SHA256.
15 |
16 | Raise and return 403 if not authorized.
17 |
18 | Args:
19 | payload_body: original request body to verify (request.body())
20 | signature_header: header received from GitHub (x-hub-signature-256)
21 | """
22 | if not WEBHOOK_SECRET:
23 | # If the secret is not set, we can't verify the signature
24 | return True
25 | if not signature_header:
26 | return False
27 | hash_object = hmac.new(
28 | WEBHOOK_SECRET.encode('utf-8'),
29 | msg=payload_body,
30 | digestmod=hashlib.sha256
31 | )
32 | expected_signature = "sha256=" + hash_object.hexdigest()
33 | if not hmac.compare_digest(expected_signature, signature_header):
34 | return False
35 | return True
--------------------------------------------------------------------------------
/sweepai/utils/html_extractor.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import requests
4 | from bs4 import BeautifulSoup
5 |
6 | # from llama_index import download_loader
7 |
8 |
9 | def parse_html(html):
10 | soup = BeautifulSoup(html)
11 |
12 | meta_properties = [
13 | "og:description",
14 | "og:site_name",
15 | "og:title",
16 | "og:type",
17 | "og:url",
18 | ]
19 |
20 | meta = {}
21 |
22 | for property_name in meta_properties:
23 | try:
24 | tag = soup.find("meta", property=property_name)
25 | if tag:
26 | meta[property_name] = str(tag.get("content", None))
27 | except AttributeError:
28 | meta[property_name] = None
29 |
30 | for ignore_tag in soup(["script", "style"]):
31 | ignore_tag.decompose()
32 |
33 | title = soup.title.string if soup.title else ""
34 | content = soup.body.get_text() if soup.body else ""
35 | links = []
36 |
37 | for a in soup.find_all("a", href=True):
38 | links.append({"title": a.text.strip(), "link": a["href"]})
39 |
40 | content = re.sub(r"[\n\r\t]+", "\n", content)
41 | content = re.sub(r" +", " ", content)
42 | content = re.sub(r"[\n ]{3,}", "\n\n", content)
43 | content = content.strip()
44 |
45 | return {"meta": meta, "title": title, "content": content}
46 |
47 |
48 | def download_html(url: str) -> str:
49 | # SimpleWebPageReader = download_loader("SimpleWebPageReader")
50 | # loader = SimpleWebPageReader()
51 | # document, *_ = loader.load_data(urls=[url])
52 | # return document.text
53 | return requests.get(url).text
54 |
55 |
56 | def extract_info(url):
57 | html = download_html(url)
58 | data = parse_html(html)
59 | return data
60 |
61 |
62 | def extract_links(text):
63 | pattern = r"\b(?:(?:https?|ftp)://|www\.)\S+\b"
64 | return list(set(re.findall(pattern, text)))
65 |
--------------------------------------------------------------------------------
/sweepai/utils/majority_vote.py:
--------------------------------------------------------------------------------
1 | import functools
2 |
3 | def majority_vote_decorator(num_samples, voting_func):
4 | def decorator(func):
5 | @functools.wraps(func)
6 | def wrapper(*args, **kwargs):
7 | outcomes = []
8 | for i in range(num_samples):
9 | # Set the seed for each iteration
10 | kwargs['seed'] = i
11 | outcome = func(*args, **kwargs)
12 | outcomes.append(outcome)
13 | # Apply the voting function to the outcomes
14 | majority_outcome = voting_func(outcomes)
15 | return majority_outcome
16 | return wrapper
17 | return decorator
--------------------------------------------------------------------------------
/sweepai/utils/patch_utils.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | _hdr_pat = re.compile("^@@ -(\d+),?(\d+)? \+(\d+),?(\d+)? @@$")
4 |
5 |
6 | def apply_patch(s, patch, revert=False):
7 | """
8 | Apply unified diff patch to string s to recover newer string.
9 | If revert is True, treat s as the newer string, recover older string.
10 | """
11 | s = s.splitlines(True)
12 | p = patch.splitlines(True)
13 | t = ""
14 | i = sl = 0
15 | (midx, sign) = (1, "+") if not revert else (3, "-")
16 | while i < len(p) and p[i].startswith(("---", "+++")):
17 | i += 1 # skip header lines
18 | while i < len(p):
19 | m = _hdr_pat.match(p[i])
20 | if not m:
21 | raise Exception("Cannot process diff")
22 | i += 1
23 | l = int(m.group(midx)) - 1 + (m.group(midx + 1) == "0") # noqa: E741
24 | t += "".join(s[sl:l])
25 | sl = l
26 | while i < len(p) and p[i][0] != "@":
27 | if i + 1 < len(p) and p[i + 1][0] == "\\":
28 | line = p[i][:-1]
29 | i += 2
30 | else:
31 | line = p[i]
32 | i += 1
33 | if len(line) > 0:
34 | if line[0] == sign or line[0] == " ":
35 | t += line[1:]
36 | sl += line[0] != sign
37 | t += "".join(s[sl:])
38 | return t
39 |
40 |
41 | if __name__ == "__main__":
42 | patch_output = """"""
43 |
44 | original_file_path = ""
45 |
46 | original_content = open(original_file_path).read()
47 | patched_content = apply_patch(original_content, patch_output)
48 | print(patched_content)
49 |
--------------------------------------------------------------------------------
/sweepai/utils/progress_test.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import patch
2 |
3 | from sweepai.utils.progress import create_index
4 |
5 |
6 | @patch("sweepai.utils.progress.global_mongo_client")
7 | def test_create_index(mock_mongo_client):
8 | mock_db = mock_mongo_client.return_value
9 | mock_collection = mock_db.__getitem__.return_value
10 |
11 | create_index()
12 |
13 | mock_collection.create_index.assert_called_once_with("tracking_id", unique=True)
14 |
--------------------------------------------------------------------------------
/sweepai/utils/regex_utils.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | def xml_pattern(
5 | tags: str,
6 | name: str | None = None,
7 | add_newlines: bool = True,
8 | **kwargs: dict[str, str],
9 | ) -> str:
10 | name = name or tags
11 | new_lines = "\n" if add_newlines else ""
12 | if kwargs:
13 | kwargs_pattern = "\s+" + r"\s+".join(
14 | rf"{key}=\"(?P<{value}>.*?)\"" for key, value in kwargs.items()
15 | )
16 | else:
17 | kwargs_pattern = ""
18 | return rf"<{tags}{kwargs_pattern}>{new_lines}(?P<{name}>.*?){new_lines}{tags}>"
19 |
20 |
21 | def search_xml(content: str, tag: str, **kwargs) -> str:
22 | return re.search(xml_pattern(tag, name=tag, **kwargs), content, re.DOTALL).group(
23 | tag
24 | )
25 |
26 |
27 | if __name__ == "__main__":
28 | pattern = xml_pattern("additional_changes", required="additional_changes_required")
29 | print(pattern)
30 | example_template = """\
31 |
32 | Test
33 | """
34 | print(re.match(pattern, example_template))
35 |
--------------------------------------------------------------------------------
/sweepai/utils/safe_pqueue.py:
--------------------------------------------------------------------------------
1 | import queue
2 | import threading
3 |
4 |
5 | class SafePriorityQueue:
6 | def __init__(self):
7 | self.q = queue.PriorityQueue()
8 | self.lock = threading.Lock()
9 |
10 | def put(self, priority: int, event):
11 | try:
12 | with self.lock:
13 | self.q.put((priority, event))
14 | self._invalidate_lower_priority(priority)
15 | except Exception:
16 | pass
17 |
18 | def get(self):
19 | with self.lock:
20 | return self.q.get()[1] # Only return the event, not the priority
21 |
22 | def empty(self):
23 | with self.lock:
24 | return self.q.empty()
25 |
26 | def _invalidate_lower_priority(self, priority: int):
27 | temp_q = queue.PriorityQueue()
28 | while not self.q.empty():
29 | p, e = self.q.get()
30 | if p <= priority:
31 | temp_q.put((p, e))
32 | self.q = temp_q
33 |
--------------------------------------------------------------------------------
/sweepai/utils/scorer_test.py:
--------------------------------------------------------------------------------
1 | from sweepai.utils.scorer import get_scores
2 |
3 |
4 | def test_days_since_last_modified_scores():
5 | # Given: Two file score factors
6 | factors_recent_first = [(1, 10, 1), (1, 10, 30)]
7 |
8 | # When: We calculate scores
9 | scores_recent_first = get_scores(factors_recent_first)
10 |
11 | # Then: Verify the recent modification has a higher score
12 | assert scores_recent_first[0] > scores_recent_first[1]
13 |
14 |
15 | def test_commit_count_effect_on_scores():
16 | # Given: Two file score factors with different commit counts but same modified days
17 | factors_commit_count = [(1, 10, 1), (1, 20, 1)]
18 |
19 | # When: We calculate scores
20 | scores_commit_count = get_scores(factors_commit_count)
21 |
22 | # Then: Verify the higher commit count has a higher score
23 | assert scores_commit_count[0] < scores_commit_count[1]
24 |
--------------------------------------------------------------------------------
/sweepai/utils/slack_utils.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from loguru import logger
4 | from slack_sdk import WebClient
5 | from slack_sdk.errors import SlackApiError
6 |
7 | from sweepai.config.server import SLACK_API_KEY
8 |
9 | def get_thread_by_thread_ts(client: WebClient, channel_id: int, thread_ts: int):
10 | response = client.conversations_replies(
11 | channel=channel_id,
12 | ts=thread_ts
13 | )
14 |
15 | if response["ok"]:
16 | return response["messages"]
17 | else:
18 | print(f"Error fetching thread: {response['error']}")
19 | return None
20 |
21 | def add_slack_context(summary) -> str:
22 | result = ""
23 | if not SLACK_API_KEY:
24 | return result
25 | slack_link_match = re.search(r'(https://[\w-]+\.slack\.com/archives/\w+/p\d+)', summary)
26 | if not slack_link_match:
27 | return result
28 | slack_link = slack_link_match.group(1)
29 | slack_client = WebClient(token=SLACK_API_KEY)
30 | try:
31 | # Extract channel and message_ts from the Slack link
32 | link_parts = slack_link.split('/')
33 | slack_channel_id = link_parts[-2]
34 | slack_message_ts = link_parts[-1][1:] # Remove the 'p' prefix
35 | # you need to add a dot six places from the right
36 | slack_message_ts = f"{slack_message_ts[:-6]}.{slack_message_ts[-6:]}"
37 | # Fetch the message object
38 | thread_messages = get_thread_by_thread_ts(client=slack_client, channel_id=slack_channel_id, thread_ts=slack_message_ts)
39 | if len(thread_messages) > 0:
40 | result += f"\n\nThe following slack thread was attached to {slack_link}:\n\n"
41 | for idx, thread_message in enumerate(thread_messages):
42 | result += f"Message {idx}: {thread_message['text']}\n" if "text" in thread_message else ""
43 | result += ""
44 | except SlackApiError as e:
45 | logger.error(f"Error fetching Slack message or thread: {e}")
46 | return result
47 |
48 | if __name__ == "__main__":
49 | url = ""
50 | result = add_slack_context(url)
51 | print(result)
--------------------------------------------------------------------------------
/sweepai/utils/streamable_functions.py:
--------------------------------------------------------------------------------
1 | from typing import Callable, Generator, ParamSpec, TypeVar, Generic
2 |
3 | InputType = ParamSpec('InputType')
4 | YieldType = TypeVar('YieldType')
5 | ReturnType = TypeVar('ReturnType')
6 |
7 | class StreamableFunction(Generic[InputType, ReturnType, YieldType]):
8 | """
9 | The purpose of streamable function is to allow for the streaming of a function's intermediate results.
10 | This is great because you can call the function normally, and it will return the function's return value,
11 | or the last yielded value, if the function has no return.
12 | But you can also call .stream() on the function, and it will return a generator that yields the intermediate results.
13 | """
14 | def __init__(self, stream: Callable[InputType, Generator[YieldType, None, ReturnType]]):
15 | self.stream: Callable[InputType, Generator[YieldType, None, ReturnType]] = stream
16 |
17 | def __call__(self, *args: InputType.args, **kwargs: InputType.kwargs) -> YieldType | ReturnType:
18 | """
19 | Returns the last yield or return result of the stream
20 | """
21 | result: YieldType | ReturnType = None
22 | try:
23 | generator = self.stream(*args, **kwargs)
24 | while True:
25 | result = next(generator)
26 | except StopIteration as e:
27 | return e.value if e.value is not None else result
28 |
29 | def streamable(stream: Callable[InputType, Generator[YieldType, None, ReturnType]]) -> StreamableFunction[InputType, ReturnType, YieldType]:
30 | return StreamableFunction(stream)
31 |
32 | if __name__ == "__main__":
33 | @streamable
34 | def stream():
35 | for i in range(10):
36 | yield i
37 | return -1
38 |
39 | result = stream()
40 | print(result)
41 |
42 | for message in stream.stream():
43 | print(message)
44 |
--------------------------------------------------------------------------------
/sweepai/utils/tiktoken_utils.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 |
4 | import tiktoken
5 |
6 |
7 |
8 | TIKTOKEN_CACHE_DIR = "/tmp/cache/tiktoken"
9 |
10 |
11 | class Tiktoken:
12 | def __init__(self):
13 | openai_models = [
14 | "gpt-3.5-turbo",
15 | "gpt-3.5-turbo-1106",
16 | "gpt-4",
17 | "gpt-4-32k",
18 | "gpt-4-32k-0613",
19 | "gpt-4-1106-preview",
20 | "gpt-4-0125-preview",
21 | ]
22 | self.openai_models = {
23 | model: tiktoken.encoding_for_model(model) for model in openai_models
24 | }
25 |
26 | def count(self, text: str, model: str = "gpt-4") -> int:
27 | return len(self.openai_models[model].encode(text, disallowed_special=()))
28 |
29 | def truncate_string(
30 | self, text: str, model: str = "gpt-4", max_tokens: int = 8192
31 | ) -> str:
32 | tokens = self.openai_models[model].encode(text)[:max_tokens - 1]
33 | return self.openai_models[model].decode(tokens)
34 |
--------------------------------------------------------------------------------
/sweepai/utils/timer.py:
--------------------------------------------------------------------------------
1 | import time
2 | from dataclasses import dataclass
3 |
4 | from loguru import logger
5 |
6 |
7 | @dataclass
8 | class Timer:
9 | start: float = 0
10 | end: float = 0
11 | time_elapsed: float = -1
12 | do_print: bool = True
13 |
14 | def __enter__(self):
15 | self.start = time.time()
16 | return self
17 |
18 | def __exit__(self, exc_type, exc_value, traceback):
19 | self.end = time.time()
20 | self.time_elapsed = self.end - self.start
21 | logger.debug(f"Time elapsed: {self.time_elapsed:.2f}")
22 |
23 |
24 | if __name__ == "__main__":
25 | with Timer() as t:
26 | time.sleep(1)
27 | print(t.time_elapsed)
28 | assert t.time_elapsed > 0.9
29 |
--------------------------------------------------------------------------------
/sweepai/utils/utils_test.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from sweepai.utils.code_validators import check_syntax
4 |
5 |
6 | @pytest.mark.parametrize(
7 | "file_path, code, expected_validity, expected_message",
8 | [
9 | ("file.tsx", "let x = 1;", True, ""),
10 | ("file.tsx", "let x = ;", False, "Invalid syntax found within or before the lines 0-0, displayed below:\nlet x = ;"),
11 | ("file.py", "x = 1", True, ""),
12 | ],
13 | )
14 | def test_check_syntax(file_path, code, expected_validity, expected_message):
15 | validity, message = check_syntax(file_path, code)
16 | assert validity == expected_validity
17 | assert message == expected_message
18 |
--------------------------------------------------------------------------------
/sweepai/utils/validate_license.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from sweepai.config.server import LICENSE_KEY
3 |
4 | def validate_license():
5 | # Validate the license key
6 | if LICENSE_KEY is None:
7 | raise ValueError("No license key provided, please set the LICENSE_KEY environment variable or get a license key from https://deploy.sweep.dev.")
8 | response = requests.post(
9 | "https://api.keygen.sh/v1/accounts/sweep-dev/licenses/actions/validate-key",
10 | headers={
11 | "Content-Type": "application/vnd.api+json",
12 | "Accept": "application/vnd.api+json",
13 | },
14 | json={"meta": {"key": LICENSE_KEY}},
15 | )
16 | if response.status_code != 200:
17 | raise ValueError("License key is invalid or expired. Please contact us at team@sweep.dev to upgrade to an enterprise license.")
18 | obj = response.json()
19 | if obj["data"]["attributes"]["status"] not in ("ACTIVE", "EXPIRING"):
20 | raise ValueError("License key is not active. Please contact us at team@sweep.dev to upgrade to an enterprise license.")
21 | return True
22 |
23 | if __name__ == "__main__":
24 | assert validate_license()
25 |
--------------------------------------------------------------------------------
/sweepai/web/event_utils.py:
--------------------------------------------------------------------------------
1 |
2 | from github import Github
3 |
4 | from sweepai.utils.github_utils import get_github_client, get_installation_id
5 | from sweepai.web.events import Account, Installation, IssueRequest
6 |
7 | def fetch_issue_request(org_name: str,
8 | repo_name: str,
9 | issue_number: str,
10 | issue_url: str = "",
11 | __version__: str = "0"):
12 |
13 | print("Fetching installation ID...")
14 | installation_id = get_installation_id(org_name)
15 | print("Fetching access token...")
16 | _token, g = get_github_client(installation_id)
17 | g: Github = g
18 | print("Fetching repo...")
19 | issue = g.get_repo(f"{org_name}/{repo_name}").get_issue(int(issue_number))
20 |
21 | issue_request = IssueRequest(
22 | action="labeled",
23 | issue=IssueRequest.Issue(
24 | title=issue.title,
25 | number=int(issue_number),
26 | html_url=issue_url,
27 | user=IssueRequest.Issue.User(
28 | login=issue.user.login,
29 | type="User",
30 | ),
31 | body=issue.body,
32 | labels=[
33 | IssueRequest.Issue.Label(
34 | name="sweep",
35 | ),
36 | ],
37 | assignees=None,
38 | pull_request=None,
39 | ),
40 | repository=IssueRequest.Issue.Repository(
41 | full_name=issue.repository.full_name,
42 | description=issue.repository.description,
43 | ),
44 | assignee=IssueRequest.Issue.Assignee(login=issue.user.login),
45 | installation=Installation(
46 | id=installation_id,
47 | account=Account(
48 | id=issue.user.id,
49 | login=issue.user.login,
50 | type="User",
51 | ),
52 | ),
53 | sender=IssueRequest.Issue.User(
54 | login=issue.user.login,
55 | type="User",
56 | ),
57 | )
58 | return issue_request
59 |
--------------------------------------------------------------------------------
/sweepai/web/health.py:
--------------------------------------------------------------------------------
1 | import psutil
2 | import redis
3 | from fastapi import FastAPI
4 | from fastapi.responses import JSONResponse
5 | from loguru import logger
6 | from pymongo import MongoClient
7 |
8 | from sweepai.config.server import IS_SELF_HOSTED, MONGODB_URI, REDIS_URL
9 |
10 | app = FastAPI()
11 |
12 |
13 | def check_sandbox_health() -> str:
14 | return "UP"
15 |
16 |
17 | def check_mongodb_health() -> str:
18 | try:
19 | client = MongoClient(MONGODB_URI)
20 | client.admin.command("ismaster")
21 | return "UP"
22 | except Exception as e:
23 | logger.exception(f"Error checking MongoDB health: {e}")
24 | return "DOWN"
25 |
26 |
27 | def check_redis_health() -> str:
28 | try:
29 | redis_client = redis.Redis.from_url(REDIS_URL)
30 | redis_client.ping()
31 | return "UP"
32 | except Exception as e:
33 | logger.exception(f"Error checking Redis health: {e}")
34 | return "DOWN"
35 |
36 |
37 | @app.get("/health")
38 | def health_check():
39 | sandbox_status = check_sandbox_health()
40 | mongo_status = check_mongodb_health() if not IS_SELF_HOSTED else None
41 | redis_status = check_redis_health()
42 |
43 | cpu_usage = psutil.cpu_percent(interval=0.1)
44 | memory_info = psutil.virtual_memory()
45 | disk_usage = psutil.disk_usage("/")
46 | network_traffic = psutil.net_io_counters()
47 |
48 | status = {
49 | "status": "UP",
50 | "details": {
51 | "sandbox": {
52 | "status": sandbox_status,
53 | },
54 | "mongodb": {
55 | "status": mongo_status,
56 | },
57 | "redis": {
58 | "status": redis_status,
59 | },
60 | "system_resources": {
61 | "cpu_usage": cpu_usage,
62 | "memory_usage": memory_info.used,
63 | "disk_usage": disk_usage.used,
64 | "network_traffic": {
65 | "bytes_sent": network_traffic.bytes_sent,
66 | "bytes_received": network_traffic.bytes_recv,
67 | },
68 | },
69 | },
70 | }
71 |
72 | return JSONResponse(status_code=200, content=status)
73 |
--------------------------------------------------------------------------------
/sweepai/web/health_test.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from unittest.mock import patch
3 |
4 | from fastapi.testclient import TestClient
5 |
6 | from sweepai.web.health import (
7 | app,
8 | check_mongodb_health,
9 | check_redis_health,
10 | check_sandbox_health,
11 | )
12 |
13 |
14 | @unittest.skip("Fails")
15 | class TestHealth(unittest.TestCase):
16 | def setUp(self):
17 | self.client = TestClient(app)
18 |
19 | @patch("sweepai.health.requests.get")
20 | def test_check_sandbox_health(self, mock_get):
21 | mock_get.return_value.status_code = 200
22 | response = check_sandbox_health()
23 | self.assertEqual(response, "UP")
24 |
25 | mock_get.return_value.status_code = 500
26 | response = check_sandbox_health()
27 | self.assertEqual(response, "DOWN")
28 |
29 | @patch("sweepai.health.MongoClient")
30 | def test_check_mongodb_health(self, mock_client):
31 | mock_client.admin.command.return_value = True
32 | response = check_mongodb_health()
33 | self.assertEqual(response, "UP")
34 |
35 | mock_client.admin.command.side_effect = Exception()
36 | response = check_mongodb_health()
37 | self.assertEqual(response, "DOWN")
38 |
39 | @patch("sweepai.health.redis.Redis")
40 | def test_check_redis_health(self, mock_redis):
41 | mock_redis.ping.return_value = True
42 | response = check_redis_health()
43 | self.assertEqual(response, "UP")
44 |
45 | mock_redis.ping.side_effect = Exception()
46 | response = check_redis_health()
47 | self.assertEqual(response, "DOWN")
48 |
49 | def test_health_check(self):
50 | response = self.client.get("/health")
51 | self.assertEqual(response.status_code, 200)
52 | self.assertIn("status", response.json())
53 | self.assertIn("details", response.json())
54 |
--------------------------------------------------------------------------------
/sweepai/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Sweep AI
6 |
7 |
23 |
24 |
25 | Welcome to Sweep AI
26 |
27 | {% if license_expired %}
28 |
29 |
Error: Your license is either invalid or has expired. Please renew to continue using all features by contacting us at team@sweep.dev.
30 |
31 | {% endif %}
32 | {% if not license_expired %}
33 |
34 | {% endif %}
35 | Version {{version}}
36 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/__init__.py
--------------------------------------------------------------------------------
/tests/e2e/test_file_tests.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 | import sys
4 |
5 | def test_run_file_tests():
6 | list_of_files = ["sweepai/core/repo_parsing_utils.py", "sweepai/utils/github_utils.py", "sweepai/agents/modify_file.py", "sweepai/core/context_pruning.py", "sweepai/agents/modify_bot.py"]
7 |
8 | for file in list_of_files:
9 | print(f"Running file: {file}")
10 | commands = ["python", f"{file}"]
11 | result = subprocess.run(" ".join(commands), capture_output=True, text=True, shell=True)
12 | error_message = f"{file.split(os.path.sep)[-1]} failed"
13 | if error_message in result.stderr:
14 | sys.exit(f"Error in file: {file}\n{result.stderr}")
15 |
16 | if __name__ == "__main__":
17 | test_run_file_tests()
18 |
--------------------------------------------------------------------------------
/tests/e2e/test_pr_review.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import traceback
3 |
4 | from sweepai.api import global_threads
5 | from sweepai.handlers.review_pr import review_pr
6 | from sweepai.utils.github_utils import get_github_client, get_installation_id
7 |
8 |
9 | def test_e2e_pr_review():
10 | try:
11 | repo_name = "sweepai/e2e" # for e2e test this is hardcoded
12 | installation_id = get_installation_id("sweepai")
13 | pr_number = 1349
14 | _, g = get_github_client(installation_id)
15 | repo = g.get_repo(repo_name)
16 | pr = repo.get_pull(pr_number)
17 |
18 | review_pr(
19 | "E2E-test-user",
20 | pr,
21 | repo,
22 | installation_id,
23 | pr_labelled=True,
24 | )
25 | except AssertionError as e:
26 | for thread in global_threads:
27 | thread.join()
28 | print(f"Assertions failed with error: {e}")
29 | sys.exit(1)
30 | except Exception as e:
31 | for thread in global_threads:
32 | thread.join()
33 | stack_trace = traceback.format_exc()
34 | print(f"Failed with error: {e}\nTraceback: {stack_trace}")
35 | sys.exit(1)
36 |
37 |
38 | if __name__ == "__main__":
39 | test_e2e_pr_review()
40 |
--------------------------------------------------------------------------------
/tests/events/create_None_34875225368.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/create_None_34875225368.pkl
--------------------------------------------------------------------------------
/tests/events/create_None_34875316547.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/create_None_34875316547.pkl
--------------------------------------------------------------------------------
/tests/events/create_None_34875548354.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/create_None_34875548354.pkl
--------------------------------------------------------------------------------
/tests/events/create_None_34875679257.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/create_None_34875679257.pkl
--------------------------------------------------------------------------------
/tests/events/issue_closed_11503916179.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_closed_11503916179.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875231171.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875231171.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875260242.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875260242.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875326442.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875326442.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875330267.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875330267.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875495470.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875495470.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875496046.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875496046.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875575948.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875575948.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875580479.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875580479.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875663842.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875663842.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875664837.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875664837.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875665614.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875665614.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875673952.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875673952.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875674995.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875674995.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875675569.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875675569.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875703608.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875703608.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875703833.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875703833.pkl
--------------------------------------------------------------------------------
/tests/events/issue_comment_created_34875705752.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_comment_created_34875705752.pkl
--------------------------------------------------------------------------------
/tests/events/issue_deployed_11503790917.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_deployed_11503790917.pkl
--------------------------------------------------------------------------------
/tests/events/issue_deployed_11503827904.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_deployed_11503827904.pkl
--------------------------------------------------------------------------------
/tests/events/issue_deployed_11503917336.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_deployed_11503917336.pkl
--------------------------------------------------------------------------------
/tests/events/issue_labeled_11503901425.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_labeled_11503901425.pkl
--------------------------------------------------------------------------------
/tests/events/issue_labeled_11503959359.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_labeled_11503959359.pkl
--------------------------------------------------------------------------------
/tests/events/issue_review_requested_11503787821.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_review_requested_11503787821.pkl
--------------------------------------------------------------------------------
/tests/events/issue_unlabeled_11503901079.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/issue_unlabeled_11503901079.pkl
--------------------------------------------------------------------------------
/tests/events/pull_request_closed_34875582679.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/pull_request_closed_34875582679.pkl
--------------------------------------------------------------------------------
/tests/events/pull_request_opened_34875229202.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/pull_request_opened_34875229202.pkl
--------------------------------------------------------------------------------
/tests/events/pull_request_opened_34875324597.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/pull_request_opened_34875324597.pkl
--------------------------------------------------------------------------------
/tests/events/pull_request_opened_34875574148.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/pull_request_opened_34875574148.pkl
--------------------------------------------------------------------------------
/tests/events/pull_request_opened_34875703602.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/pull_request_opened_34875703602.pkl
--------------------------------------------------------------------------------
/tests/events/push_None_34875568335.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/push_None_34875568335.pkl
--------------------------------------------------------------------------------
/tests/events/push_None_34875697750.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/events/push_None_34875697750.pkl
--------------------------------------------------------------------------------
/tests/jsons/e2e_branch_change.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "title": "Sweep: Change the install app button colour to pink",
5 | "number": 32,
6 | "html_url": "https://github.com/sweepai/e2e/issues/32",
7 | "user": {
8 | "login": "MartinYe1234",
9 | "type": "User"
10 | },
11 | "body": "Branch: dev",
12 | "labels": [
13 | {
14 | "name": "sweep"
15 | }
16 | ],
17 | "assignees": null,
18 | "pull_request": null
19 | },
20 | "repository": {
21 | "full_name": "sweepai/e2e",
22 | "description": null
23 | },
24 | "assignee": {
25 | "login": "MartinYe1234"
26 | },
27 | "installation": {
28 | "id": 36855882,
29 | "account": {
30 | "id": 52641447,
31 | "login": "MartinYe1234",
32 | "type": "User"
33 | }
34 | },
35 | "sender": {
36 | "login": "MartinYe1234",
37 | "type": "User"
38 | }
39 | }
--------------------------------------------------------------------------------
/tests/jsons/e2e_button_to_green.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "title": "Sweep: Change the install app button color to green",
5 | "number": 1,
6 | "html_url": "https://github.com/sweepai/e2e/issues/1",
7 | "user": {
8 | "login": "MartinYe1234",
9 | "type": "User"
10 | },
11 | "body": "### Details\nReference CallToAction.tsx to find the button\n\n\n\nChecklist
\n\n- [X] Modify `src/components/CallToAction.tsx` \u2713 https://github.com/sweepai/e2e/commit/0ef6250fe662c13f62201808baf2d9cb376134af [Edit](https://github.com/sweepai/e2e/edit/sweep/change_the_install_app_button_color_to_g_6f507/src/components/CallToAction.tsx#L55-L64)\n- [X] Running GitHub Actions for `src/components/CallToAction.tsx` \u2713 [Edit](https://github.com/sweepai/e2e/edit/sweep/change_the_install_app_button_color_to_g_6f507/src/components/CallToAction.tsx#L55-L64)\n \n",
12 | "labels": [
13 | {
14 | "name": "sweep"
15 | }
16 | ],
17 | "assignees": null,
18 | "pull_request": null
19 | },
20 | "repository": {
21 | "full_name": "sweepai/e2e",
22 | "description": null
23 | },
24 | "assignee": {
25 | "login": "MartinYe1234"
26 | },
27 | "installation": {
28 | "id": 36855882,
29 | "account": {
30 | "id": 52641447,
31 | "login": "MartinYe1234",
32 | "type": "User"
33 | }
34 | },
35 | "sender": {
36 | "login": "MartinYe1234",
37 | "type": "User"
38 | }
39 | }
--------------------------------------------------------------------------------
/tests/modify_tests/modify_test.py:
--------------------------------------------------------------------------------
1 | from sweepai.utils.diff import generate_new_file_from_patch
2 |
3 |
4 | def run_test(old_file, message):
5 | print(generate_new_file_from_patch(message, old_file)[0])
6 |
--------------------------------------------------------------------------------
/tests/modify_tests/test_tabs.py:
--------------------------------------------------------------------------------
1 | from tests.modify_tests.modify_test import run_test
2 |
3 | run_test(
4 | old_file="""
5 | wow
6 | very cool
7 | much wow
8 | """,
9 | message="""<<<< ORIGINAL
10 | very cool
11 | ====
12 | [ works ]
13 | >>>> UPDATED""",
14 | )
15 |
--------------------------------------------------------------------------------
/tests/monitor_prod.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 |
4 | from github import Github
5 |
6 | import sweepai.config.server # NOQA
7 |
8 | g = Github(os.environ.get("GITHUB_PAT"))
9 | issue_url = "https://github.com/wwzeng1/landing-page/issues/206"
10 | issue = g.get_repo("wwzeng1/landing-page").get_issue(206)
11 |
12 | comment_id = list(issue.get_comments())[0].id
13 |
14 | while True:
15 | comment = issue.get_comment(comment_id)
16 | body = comment.body
17 | start_time = time.time()
18 | print(f"Editing comment {comment_id}...")
19 | comment.edit(body=body.replace("- [ ] ↻ Restart Sweep", "- [x] ↻ Restart Sweep"))
20 | for i in range(60):
21 | comment = issue.get_comment(comment_id)
22 | print(f"Checking comment... ({time.time() - start_time:.2f})")
23 | if "- [ ] ↻ Restart Sweep" in comment.body:
24 | print(f"Got a response in {time.time() - start_time:.2f} seconds")
25 | break
26 | time.sleep(2)
27 | time.sleep(1)
28 |
--------------------------------------------------------------------------------
/tests/notebooks/importmagic.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 23,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "data": {
10 | "text/plain": [
11 | "'utils.github_utils'"
12 | ]
13 | },
14 | "execution_count": 23,
15 | "metadata": {},
16 | "output_type": "execute_result"
17 | }
18 | ],
19 | "source": [
20 | "from importmagic import index\n",
21 | "\n",
22 | "def get_autoimport(\n",
23 | " entity_name: str,\n",
24 | " project_name: str,\n",
25 | "):\n",
26 | " my_index = index.SymbolIndex()\n",
27 | " my_index.build_index([project_name])\n",
28 | " results = my_index.symbol_scores(entity_name)\n",
29 | " if results:\n",
30 | " return results[0][1]\n",
31 | "\n",
32 | "get_autoimport(\"ClonedRepo\", \"../../sweepai\")\n"
33 | ]
34 | },
35 | {
36 | "cell_type": "code",
37 | "execution_count": null,
38 | "metadata": {},
39 | "outputs": [],
40 | "source": []
41 | }
42 | ],
43 | "metadata": {
44 | "kernelspec": {
45 | "display_name": "Python 3.10.10 ('sweepai-u_CIt3kb-py3.10')",
46 | "language": "python",
47 | "name": "python3"
48 | },
49 | "language_info": {
50 | "codemirror_mode": {
51 | "name": "ipython",
52 | "version": 3
53 | },
54 | "file_extension": ".py",
55 | "mimetype": "text/x-python",
56 | "name": "python",
57 | "nbconvert_exporter": "python",
58 | "pygments_lexer": "ipython3",
59 | "version": "3.10.10"
60 | },
61 | "orig_nbformat": 4,
62 | "vscode": {
63 | "interpreter": {
64 | "hash": "25d341f3248a096a89b9dbf6eec8e41f63aed02f6ba059df22a49224e3e8f1b0"
65 | }
66 | }
67 | },
68 | "nbformat": 4,
69 | "nbformat_minor": 2
70 | }
71 |
--------------------------------------------------------------------------------
/tests/notebooks/src/class_refactor.py:
--------------------------------------------------------------------------------
1 | class Foo:
2 | def __init__(self):
3 | self.a = 1
4 | self.b = 2 * self.a
5 |
--------------------------------------------------------------------------------
/tests/notebooks/src/helpers/test2.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 |
4 | def a_func():
5 | a = 1
6 | b = 2 * a
7 | c = a * foo() + b * 3
8 | print(b, c)
9 |
10 |
11 | def foo():
12 | return math.pow(2, 2)
13 |
--------------------------------------------------------------------------------
/tests/notebooks/src/helpers/utils.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sweepai/sweep/a8b8b67bda4f89faac9314d34e7c7d5a64f76046/tests/notebooks/src/helpers/utils.py
--------------------------------------------------------------------------------
/tests/notebooks/src/jedi_test.py:
--------------------------------------------------------------------------------
1 | from helpers.test2 import a_func
2 |
3 |
4 | def foo():
5 | a_func()
6 | return a_func()
7 |
--------------------------------------------------------------------------------
/tests/notebooks/src/mod1.py:
--------------------------------------------------------------------------------
1 | def pow(x, y):
2 | result = 1
3 | for i in range(y):
4 | result *= x
5 | return result
6 |
--------------------------------------------------------------------------------
/tests/notebooks/src/mod2.py:
--------------------------------------------------------------------------------
1 | import mod1
2 |
3 | print(mod1.pow(2, 3))
4 |
--------------------------------------------------------------------------------
/tests/notebooks/src/test2.py:
--------------------------------------------------------------------------------
1 | def a_func():
2 | typer = None
3 | update_repo = lambda git, ref, repo_dir: None
4 | get_langserve_export = lambda pyproject_path: None
5 | package_dir = ""
6 | copy_repo = lambda git, ref, repo_dir: None
7 | installed_destination_paths = []
8 | installed_exports = []
9 | REPO_DIR = ""
10 | grouped = {}
11 | for (git, ref), group_deps in grouped.items():
12 | if len(group_deps) == 1:
13 | typer.echo(f"Adding {git}@{ref}...")
14 | else:
15 | typer.echo(f"Adding {len(group_deps)} templates from {git}@{ref}")
16 | source_repo_path = update_repo(git, ref, REPO_DIR)
17 |
18 | for dep in group_deps:
19 | source_path = (
20 | source_repo_path / dep["subdirectory"]
21 | if dep["subdirectory"]
22 | else source_repo_path
23 | )
24 | pyproject_path = source_path / "pyproject.toml"
25 | if not pyproject_path.exists():
26 | typer.echo(f"Could not find {pyproject_path}")
27 | continue
28 | langserve_export = get_langserve_export(pyproject_path)
29 |
30 | # default path to package_name
31 | inner_api_path = dep["api_path"] or langserve_export["package_name"]
32 |
33 | destination_path = package_dir / inner_api_path
34 | if destination_path.exists():
35 | typer.echo(
36 | f"Folder {str(inner_api_path)} already exists. " "Skipping...",
37 | )
38 | continue
39 | copy_repo(source_path, destination_path)
40 | typer.echo(f" - Downloaded {dep['subdirectory']} to {inner_api_path}")
41 | installed_destination_paths.append(destination_path)
42 | installed_exports.append(langserve_export)
43 |
--------------------------------------------------------------------------------
/tests/perf/concurrent_fastapi.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import threading
3 | import time
4 |
5 | from fastapi import FastAPI
6 |
7 | from sweepai.utils.event_logger import logger
8 |
9 | app = FastAPI()
10 |
11 | with logger.contextualize(tracking_id="main"):
12 | logger.info(
13 | "Response code {code} HTTP/1.1 GET {url}",
14 | code=200,
15 | url="https://loki_handler.io",
16 | )
17 |
18 |
19 | def get_hash():
20 | return hashlib.sha256(str(time.time()).encode()).hexdigest()[:10]
21 |
22 |
23 | def worker_job(tracking_id: str = None):
24 | logger.bind(tracking_id=tracking_id)
25 | with logger.contextualize(tracking_id=tracking_id):
26 | logger.info(f"Start: inside the with statement from worker {tracking_id}")
27 | time.sleep(3)
28 | logger.info(f"End: inside the with statement from worker {tracking_id}")
29 | logger.info("Outside the with statement")
30 |
31 |
32 | @app.post("/start_job/")
33 | async def start_job():
34 | with logger.contextualize(tracking_id="main"):
35 | logger.info("Starting job")
36 | thread = threading.Thread(target=worker_job, args=(get_hash(),))
37 | thread.start()
38 | return {"message": "Job started"}
39 |
--------------------------------------------------------------------------------
/tests/perf/stress_test.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import json
3 | import time
4 |
5 | import aiohttp
6 | from tqdm import tqdm
7 |
8 |
9 | async def post_request(session, url, data, headers, progress_bar):
10 | async with session.post(url, json=data, headers=headers) as response:
11 | print(await response.text())
12 | progress_bar.update(1)
13 |
14 |
15 | num_runs = 10
16 |
17 |
18 | async def main():
19 | start_time = time.time()
20 | progress_bar = tqdm(total=num_runs)
21 | async with aiohttp.ClientSession() as session:
22 | tasks = []
23 | for i in range(num_runs):
24 | data = json.load(open("tests/jsons/branch_push.json", "r"))
25 | task = asyncio.create_task(
26 | post_request(
27 | session,
28 | "http://127.0.0.1:8080",
29 | data,
30 | {"X-GitHub-Event": "push"},
31 | progress_bar,
32 | )
33 | )
34 | tasks.append(task)
35 | await asyncio.gather(*tasks)
36 | progress_bar.close()
37 | print(f"Finished in {time.time() - start_time}")
38 |
39 |
40 | if __name__ == "__main__":
41 | asyncio.run(main())
42 |
--------------------------------------------------------------------------------
/tests/ping_webhook.py:
--------------------------------------------------------------------------------
1 | import json
2 | import time
3 |
4 | import requests
5 |
6 | # if __name__ == "__main__":
7 | # for i in range(10):
8 | # start_time = time.time()
9 | # print(f"Sending {i}th attempt")
10 | # response = requests.post(
11 | # # "http://127.0.0.1:8080",
12 | # "https://sweep-prod.ngrok.dev",
13 | # json=json.load(open("tests/jsons/opened_pull.json", "r")),
14 | # headers={"X-GitHub-Event": "test"},
15 | # )
16 | # print(f"Completed in {time.time() - start_time}s")
17 | # print(response)
18 | # print(response.text)
19 |
20 | import json
21 | import time
22 |
23 | import requests
24 |
25 | if __name__ == "__main__":
26 |
27 | start_time = time.time()
28 |
29 | from fastapi.testclient import TestClient
30 | from sweepai.api import app
31 | def send_request(issue_request):
32 | with TestClient(app) as client:
33 | response = client.post(
34 | "/", json=issue_request, headers={"X-GitHub-Event": "pull_request"}
35 | )
36 | print(response) # or return response, depending on your needs
37 | issue_request = json.loads(open("tests/jsons/pull_request_closed.json", "r").read())
38 | send_request(issue_request)
39 |
--------------------------------------------------------------------------------
/tests/redirect_api.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import requests
4 | from dotenv import load_dotenv
5 | from fastapi import FastAPI, Request
6 |
7 | load_dotenv(dotenv_path=".env")
8 |
9 | app = FastAPI()
10 |
11 | DEV_URL = os.environ.get("DEV_URL", "http://127.0.0.1:8080")
12 | BACKUP_URL = os.environ.get("BACKUP_DEV_URL", "http://127.0.0.1:8080")
13 | HEALTH_ENDPOINT = "/health"
14 |
15 | assert DEV_URL is not None, "DEV_URL must be set"
16 | assert BACKUP_URL is not None, "BACKUP_DEV_URL must be set"
17 |
18 | print(f"DEV_URL: {DEV_URL}")
19 | print(f"BACKUP_DEV_URL: {BACKUP_URL}")
20 |
21 |
22 | def is_dev_up():
23 | response = requests.get(f"{DEV_URL}{HEALTH_ENDPOINT}")
24 | return response.status_code == 200
25 |
26 |
27 | @app.api_route(
28 | "/{path:path}",
29 | methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"],
30 | include_in_schema=False,
31 | )
32 | async def forward_request(path: str, request: Request):
33 | target_url = DEV_URL if is_dev_up() else BACKUP_URL
34 | print(f"Forwarding request to {target_url}/{path}")
35 | request_json = None
36 | try:
37 | request_json = await request.json()
38 | except:
39 | pass
40 | resp = requests.request(
41 | request.method,
42 | f"{target_url}/{path}",
43 | headers=request.headers,
44 | params=request.query_params,
45 | json=request_json,
46 | timeout=10.0,
47 | )
48 | resp.raise_for_status()
49 | return resp.text
50 |
--------------------------------------------------------------------------------
/tests/rerun_chat_modify_direct.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 |
4 | from sweepai.agents.modify import modify
5 | from sweepai.config.server import GITHUB_APP_ID, GITHUB_APP_PEM
6 | from sweepai.core.entities import FileChangeRequest
7 | from sweepai.dataclasses.code_suggestions import CodeSuggestion
8 | from sweepai.utils.github_utils import ClonedRepo, get_installation_id
9 | from sweepai.utils.github_utils import get_github_client
10 |
11 |
12 | repo_full_name = os.environ["REPO_FULL_NAME"]
13 | branch = os.environ["BRANCH"]
14 | code_suggestions_path = os.environ.get("CODE_SUGGESTIONS_PATH", "code_suggestions.json")
15 |
16 | org_name, repo = repo_full_name.split("/")
17 | installation_id = get_installation_id(org_name, GITHUB_APP_PEM, GITHUB_APP_ID)
18 | user_token, g = get_github_client(installation_id=installation_id)
19 | cloned_repo = ClonedRepo(
20 | repo_full_name,
21 | installation_id=installation_id,
22 | token=user_token,
23 | branch=branch
24 | )
25 |
26 | file_change_requests = []
27 |
28 | with open(code_suggestions_path, "r") as file:
29 | data = json.load(file)
30 | code_suggestions = [CodeSuggestion(**item) for item in data]
31 |
32 | for code_suggestion in code_suggestions:
33 | change_type = "modify"
34 | if not code_suggestion.original_code:
35 | try:
36 | cloned_repo.get_file_contents(code_suggestion.file_path)
37 | except FileNotFoundError:
38 | change_type = "create"
39 | file_change_requests.append(
40 | FileChangeRequest(
41 | filename=code_suggestion.file_path,
42 | change_type=change_type,
43 | instructions=f"\n{code_suggestion.original_code}\n\n\n\n{code_suggestion.new_code}\n",
44 | )
45 | )
46 |
47 | try:
48 | for stateful_code_suggestions in modify.stream(
49 | fcrs=file_change_requests,
50 | request="",
51 | cloned_repo=cloned_repo,
52 | relevant_filepaths=[code_suggestion.file_path for code_suggestion in code_suggestions],
53 | ):
54 | pass
55 | except Exception as e:
56 | raise e
--------------------------------------------------------------------------------
/tests/rerun_fix_github_actions_direct.py:
--------------------------------------------------------------------------------
1 | import typer
2 |
3 | from sweepai.handlers.on_failing_github_actions import on_failing_github_actions
4 | from sweepai.utils.chat_logger import ChatLogger
5 | from sweepai.utils.github_utils import get_github_client, get_installation_id
6 |
7 |
8 | def test_issue_url(
9 | pr_url: str,
10 | ):
11 | pr_url = pr_url or typer.prompt("PR URL")
12 | print("Fetching PR metadata...")
13 | (
14 | _,
15 | _,
16 | _,
17 | org_name,
18 | repo_name,
19 | _,
20 | pr_number,
21 | ) = pr_url.split("/")
22 |
23 | installation_id = get_installation_id(org_name)
24 | _token, g = get_github_client(installation_id)
25 | repo = g.get_repo(f"{org_name}/{repo_name}")
26 | pr = repo.get_pull(int(pr_number))
27 |
28 | body = pr.body
29 | if "fixes #" in body.lower():
30 | issue_number = body.lower().split("fixes #")[1].split(".")[0]
31 | issue = repo.get_issue(int(issue_number))
32 | problem_statement = issue.title + "\n" + issue.body
33 | else:
34 | problem_statement = pr.title + "\n" + pr.body
35 |
36 | on_failing_github_actions(
37 | problem_statement=problem_statement,
38 | repo=repo,
39 | username=repo.owner.login,
40 | pull_request=pr,
41 | user_token=_token,
42 | installation_id=installation_id,
43 | chat_logger=ChatLogger({"username": "on_failing_github_actions"}),
44 | )
45 |
46 |
47 | if __name__ == "__main__":
48 | try:
49 | typer.run(test_issue_url)
50 | except Exception:
51 | import pdb
52 | pdb.post_mortem()
53 | raise
54 |
--------------------------------------------------------------------------------
/tests/test_code_review.py:
--------------------------------------------------------------------------------
1 | # as an mvp this will take a pr and then review the code to generate a summary, then a comprehensive list of valid concerns
2 | # todo: citations, more complex code analysis
3 | import os
4 | from dotenv import load_dotenv
5 | from github import Github
6 | from loguru import logger
7 |
8 | from sweepai.core.review_utils import PRReviewBot, get_pr_changes
9 | from sweepai.utils.chat_logger import ChatLogger
10 |
11 | load_dotenv(dotenv_path=".env", override=True, verbose=True)
12 |
13 | # Create a GitHub instance using your access token or username and password
14 | url = "https://github.com/poulh/legacyCodeConverter/pull/2"
15 |
16 | # Specify the repository and pull request number
17 | repo_name = url.split("https://github.com/")[-1].split("/pull")[0]
18 | pr_number = int(url.split("/pull/")[1].split("/")[0])
19 |
20 | GITHUB_PAT = os.environ.get("GITHUB_PAT", None)
21 |
22 | # Get the repository and pull request objects
23 | def temp_pr_changes(url):
24 | g = Github(GITHUB_PAT)
25 | repo = g.get_repo(repo_name)
26 | pr = repo.get_pull(pr_number)
27 | # Fetch the diff
28 | pr_changes, _, _ = get_pr_changes(repo, pr)
29 | return pr_changes
30 |
31 | pr_changes = temp_pr_changes(url)
32 | breakpoint()
33 | # breakpoint()
34 | # exit()
35 | chat_logger=ChatLogger({"username": "Code Review","title": "Code Review Test",})
36 | review_bot = PRReviewBot()
37 | breakpoint()
38 |
--------------------------------------------------------------------------------
/tests/test_context_pruning.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from sweepai.core.context_pruning import (
3 | build_full_hierarchy,
4 | load_graph_from_file,
5 | RepoContextManager,
6 | get_relevant_context,
7 | )
8 | import networkx as nx
9 |
10 | class TestContextPruning(unittest.TestCase):
11 | def test_build_full_hierarchy(self):
12 | G = nx.DiGraph()
13 | G.add_edge("main.py", "database.py")
14 | G.add_edge("database.py", "models.py")
15 | G.add_edge("utils.py", "models.py")
16 | hierarchy = build_full_hierarchy(G, "main.py", 2)
17 | expected_hierarchy = """main.py
18 | ├── database.py
19 | │ └── models.py
20 | └── utils.py
21 | └── models.py
22 | """
23 | self.assertEqual(hierarchy, expected_hierarchy)
24 |
25 | def test_load_graph_from_file(self):
26 | graph = load_graph_from_file("tests/test_import_tree.txt")
27 | self.assertIsInstance(graph, nx.DiGraph)
28 | self.assertEqual(len(graph.nodes), 5)
29 | self.assertEqual(len(graph.edges), 4)
30 |
31 | def test_get_relevant_context(self):
32 | cloned_repo = ClonedRepo("sweepai/sweep", "123", "main")
33 | repo_context_manager = RepoContextManager(
34 | dir_obj=None,
35 | current_top_tree="",
36 | snippets=[],
37 | snippet_scores={},
38 | cloned_repo=cloned_repo,
39 | )
40 | query = "allow 'sweep.yaml' to be read from the user/organization's .github repository. this is found in client.py and we need to change this to optionally read from .github/sweep.yaml if it exists there"
41 | rcm = get_relevant_context(
42 | query,
43 | repo_context_manager,
44 | seed=42,
45 | ticket_progress=None,
46 | chat_logger=None,
47 | )
48 | self.assertIsInstance(rcm, RepoContextManager)
49 | self.assertTrue(len(rcm.current_top_snippets) > 0)
50 | self.assertTrue(any("client.py" in snippet.file_path for snippet in rcm.current_top_snippets))
--------------------------------------------------------------------------------
/tests/test_get_gha_logs_from_pr.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 | from sweepai.utils.ticket_rendering_utils import get_failing_gha_logs
4 | from sweepai.utils.github_utils import get_github_client, get_installation_id
5 |
6 |
7 | PR_ID = 3618
8 | INSTALLATION_ID = os.environ.get("INSTALLATION_ID")
9 | REPO_FULL_NAME = "sweepai/sweep"
10 |
11 | installation_id = get_installation_id(REPO_FULL_NAME.split("/")[0])
12 | print("Fetching access token...")
13 | _token, g = get_github_client(installation_id)
14 | print("Fetching repo...")
15 | repo = g.get_repo(f"{REPO_FULL_NAME}")
16 | pr = repo.get_pull(int(PR_ID))
17 | runs = list(repo.get_workflow_runs(branch=pr.head.ref, head_sha=pr.head.sha))
18 | failed_runs = [
19 | run for run in runs if run.conclusion == "failure"
20 | ]
21 | import pdb; pdb.set_trace()
22 | failed_gha_logs: list[str] = get_failing_gha_logs(
23 | failed_runs,
24 | INSTALLATION_ID,
25 | )
26 | import pdb; pdb.set_trace()
27 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/test_gha_extraction.py:
--------------------------------------------------------------------------------
1 | from sweepai.config.server import INSTALLATION_ID
2 | from sweepai.handlers.on_check_suite import clean_gh_logs, download_logs
3 |
4 |
5 | def test_clean_gh_logs(run_id: int, installation_id: int, repo_full_name: str):
6 | logs = download_logs(
7 | repo_full_name=repo_full_name,
8 | run_id=run_id,
9 | installation_id=installation_id
10 | )
11 | if not logs:
12 | return None
13 | logs = clean_gh_logs(logs)
14 | return logs
15 |
16 | RUN_ID = 8576903108
17 | REPO_FULL_NAME = "sweepai/sweep"
18 |
19 | logs = test_clean_gh_logs(RUN_ID, INSTALLATION_ID, REPO_FULL_NAME)
--------------------------------------------------------------------------------
/tests/test_jira_ticket.py:
--------------------------------------------------------------------------------
1 | import json
2 | from sweepai.handlers.on_jira_ticket import handle_jira_ticket
3 |
4 | def test_handle_jira_ticket():
5 | # load jira event from tests/data/jira_event.json
6 | with open("tests/data/jira_event.json") as f:
7 | event = json.load(f)
8 | # call handle_jira_ticket with the event
9 | result = handle_jira_ticket(event)
10 |
11 | if __name__ == "__main__":
12 | test_handle_jira_ticket()
--------------------------------------------------------------------------------
/tests/test_watch.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pickle
3 |
4 | from sweepai.watch import handle_event
5 |
6 | event_pickle_paths = [
7 | "pull_request_opened_34875324597.pkl",
8 | "issue_labeled_11503901425.pkl",
9 | ]
10 | for path in event_pickle_paths:
11 | event = pickle.load(open(os.path.join("tests/events", path), "rb"))
12 | handle_event(event, do_async=False)
13 |
--------------------------------------------------------------------------------