The-PR-Agent/pr-agent
🚀 PR Agent: The Original Open-Source PR Reviewer. This project is not the Qodo free tier.
Python★ 14,874+280 that day#5 on trending
C56.7/100
Duplication70
4.4% in python, javascript, jsx, bash, dockerDead code68
4.2%Complexity38
69.5% The score is jscpd's own --health model: markup, data and text left out, tests kept. The numbers below are the trending scan's.
1.47%duplicated code · 809 of 54,889 lines
65clones in code
116code files of 668 scanned
4.56%duplicated over all files · 875 clones
Most complex files
- pr_agent/algo/ai_handlers/litellm_ai_handler.py1190 cx
- tests/unittest/test_litellm_api_key_guard.py1123 cx
- pr_agent/git_providers/gitlab_provider.py834 cx
- pr_agent/git_providers/github_provider.py686 cx
- pr_agent/tools/pr_code_suggestions.py557 cx
- pr_agent/git_providers/azuredevops_provider.py540 cx
- pr_agent/algo/ai_handlers/cloud_auth.py495 cx
- pr_agent/algo/utils.py484 cx
- tests/unittest/test_litellm_callback_drain.py457 cx
- pr_agent/tools/pr_reviewer.py452 cx
Dead code 4.21% unused · 40 findings
- pr_agent/git_providers/gitlab_provider.pyunused-file
- pr_agent/git_providers/gitea_provider.pyunused-file
- pr_agent/git_providers/bitbucket_provider.pyunused-file
- pr_agent/git_providers/codecommit_provider.pyunused-file
- pr_agent/tools/pr_help_docs.pyunused-file
- pr_agent/git_providers/codecommit_client.pyunused-file
- pr_agent/git_providers/plain_diff_provider.pyunused-file
- pr_agent/git_providers/diff_parsing.pyunused-file
- pr_agent/algo/ai_handlers/langchain_ai_handler.pyunused-file
- pr_agent/algo/ai_handlers/openai_ai_handler.pyunused-file
The code number leaves out tests, fixtures, docs, examples, data files, styles, translations and vendored code, and 1 generated file: pr_agent/tools/pr_help_docs.py.
Largest clones in the code
- 48 lines in 2 placespython246 tokens
616counter = 0 617issues_iterator = iter(issues_list) 618while True: 619 if counter >= self.max_issues_to_scan: 620 get_logger().info(f"Scanned {self.max_issues_to_scan} issues, stopping") 621 break 622 try: 623 issue = next(issues_iterator) 624 except StopIteration: 625 breakFirst 10 of 48 lines.
- 47 lines in 2 placespython241 tokens
608get_logger().info('Processing issues...') 609corpus = Corpus() 610example_issue_record = Record( 611 id=f"example_issue_{repo_name_for_index}", 612 text="example_issue", 613 metadata=Metadata(repo=repo_name_for_index) 614) 615 616counter = 0 617issues_iterator = iter(issues_list)First 10 of 47 lines.
- 23 lines in 2 placespython190 tokenspr_agent/git_providers/bitbucket_provider.py:335–357pr_agent/git_providers/bitbucket_server_provider.py:168–190
335def _prepare_code_suggestion(self, suggestion: dict) -> dict | None: 336 body = suggestion["body"] 337 original_suggestion = suggestion.get('original_suggestion', None) # needed for diff code 338 if original_suggestion: 339 try: 340 existing_code = original_suggestion['existing_code'].rstrip() + "\n" 341 improved_code = original_suggestion['improved_code'].rstrip() + "\n" 342 diff = difflib.unified_diff(existing_code.split('\n'), improved_code.split('\n'), n=999) 343 patch_orig = "\n".join(diff) 344 patch = "\n".join(patch_orig.splitlines()[5:]).strip('\n')First 10 of 23 lines.
7 more
- 23 lines in 2 placespython163 tokens
- 18 lines in 2 placespython149 tokens
- 17 lines in 2 placespython125 tokens
- 20 lines in 2 placespython114 tokens
- 10 lines in 3 placespython57 tokens
- 18 lines in 2 placespython111 tokens
- 17 lines in 2 placespython103 tokens
Largest clones over all files, tests and data included
- 11 lines in 10 placespythontests62 tokenstests/unittest/test_get_max_tokens.py:88–98tests/unittest/test_get_max_tokens.py:101–111tests/unittest/test_get_max_tokens.py:114–124tests/unittest/test_get_max_tokens.py:127–137tests/unittest/test_get_max_tokens.py:140–150and 5 more
88def test_gpt54_model_max_tokens(self, monkeypatch, model): 89 fake_settings = type('', (), { 90 'config': type('', (), { 91 'custom_model_max_tokens': 0, 92 'max_model_tokens': 0 93 })() 94 })() 95 96 monkeypatch.setattr(token_budget, "get_settings", lambda: fake_settings) 97First 10 of 11 lines.
- 112 lines in 2 placestomldata files536 tokenspr_agent/settings/code_suggestions/pr_code_suggestions_prompts.toml:81–192pr_agent/settings/code_suggestions/pr_code_suggestions_prompts_not_decoupled.toml:110–221
81 one_sentence_summary: str = Field(description="A concise, single-sentence overview (up to 6 words) of the suggested improvement. Focus on the 'what'. Be ge… 82{%- if not focus_only_on_problems %} 83 label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'possible bug'… 84{%- else %} 85 label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'critical bug'… 86{%- endif %} 87 88 89class PRCodeSuggestions(BaseModel): 90 code_suggestions: List[CodeSuggestion]First 10 of 112 lines.
- 8 lines in 9 placespythontests55 tokenstests/unittest/test_get_max_tokens.py:314–321tests/unittest/test_get_max_tokens.py:366–373tests/unittest/test_get_max_tokens.py:725–733tests/unittest/test_get_max_tokens.py:760–768tests/unittest/test_get_max_tokens.py:933–941and 4 more
314def test_gpt5_thinking_model_max_tokens(self, monkeypatch, model): 315 fake_settings = type("", (), { 316 "config": type("", (), { 317 "custom_model_max_tokens": 0, 318 "max_model_tokens": 0 319 })() 320 })() 321 monkeypatch.setattr(token_budget, "get_settings", lambda: fake_settings) - 66 lines in 2 placestomldata files396 tokens
- 65 lines in 2 placestomldata files390 tokens
By format, code only
| Format | Files | Lines | Clones | Duplicated lines | Duplication |
|---|---|---|---|---|---|
| python | 115 | 54,739 | 65 | 809 | 1.48% |
| bash | 1 | 150 | 0 | 0 | 0% |
By format, all files
| Format | Files | Lines | Clones | Duplicated lines | Duplication |
|---|---|---|---|---|---|
| python | 533 | 212,529 | 812 | 9,366 | 4.41% |
| toml | 27 | 4,390 | 42 | 918 | 20.91% |
| markdown | 48 | 9,104 | 12 | 107 | 1.18% |
| yaml | 24 | 1,761 | 6 | 89 | 5.05% |
| bash | 11 | 236 | 2 | 11 | 4.66% |
| json | 4 | 150 | 1 | 31 | 20.67% |
| css | 5 | 1,428 | 0 | 0 | 0% |
| javascript | 3 | 336 | 0 | 0 | 0% |
| jsx | 3 | 306 | 0 | 0 | 0% |
| text | 6 | 133 | 0 | 0 | 0% |
Trending appearances
| Day | Rank | Stars | Files | Lines | Clones | All files | Code | Health | Commit |
|---|---|---|---|---|---|---|---|---|---|
| Nov 5, 2026 | #5 | 14,874 (+280) | 668 | 230,513 | 875 | 4.56% | 1.47% | C 56.7 | a8c6047 |
Want this for your own project? Install jscpd and run jscpd ., or measure it the way the baselines were measured.