xai-review 0.18.0__py3-none-any.whl → 0.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xai-review might be problematic. Click here for more details.
- ai_review/clients/github/pr/client.py +13 -7
- ai_review/clients/github/pr/schema/pull_request.py +6 -6
- ai_review/clients/gitlab/mr/client.py +29 -20
- ai_review/clients/gitlab/mr/schema/changes.py +5 -5
- ai_review/clients/gitlab/mr/schema/discussions.py +1 -4
- ai_review/clients/gitlab/mr/schema/notes.py +19 -0
- ai_review/services/llm/factory.py +1 -1
- ai_review/services/prompt/adapter.py +15 -15
- ai_review/services/prompt/schema.py +18 -18
- ai_review/services/review/service.py +45 -42
- ai_review/services/vcs/factory.py +1 -1
- ai_review/services/vcs/github/client.py +52 -34
- ai_review/services/vcs/gitlab/client.py +62 -44
- ai_review/services/vcs/types.py +38 -29
- ai_review/tests/suites/services/cost/__init__.py +0 -0
- ai_review/tests/suites/services/cost/test_schema.py +124 -0
- ai_review/tests/suites/services/cost/test_service.py +99 -0
- ai_review/tests/suites/services/prompt/test_adapter.py +59 -0
- ai_review/tests/suites/services/prompt/test_schema.py +18 -18
- ai_review/tests/suites/services/prompt/test_service.py +13 -11
- {xai_review-0.18.0.dist-info → xai_review-0.19.0.dist-info}/METADATA +21 -6
- {xai_review-0.18.0.dist-info → xai_review-0.19.0.dist-info}/RECORD +26 -22
- ai_review/clients/gitlab/mr/schema/comments.py +0 -19
- {xai_review-0.18.0.dist-info → xai_review-0.19.0.dist-info}/WHEEL +0 -0
- {xai_review-0.18.0.dist-info → xai_review-0.19.0.dist-info}/entry_points.txt +0 -0
- {xai_review-0.18.0.dist-info → xai_review-0.19.0.dist-info}/licenses/LICENSE +0 -0
- {xai_review-0.18.0.dist-info → xai_review-0.19.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.libs.config.llm import LLMPricingConfig, LLMConfigBase
|
|
4
|
+
from ai_review.services.cost.schema import CostReportSchema
|
|
5
|
+
from ai_review.services.cost.service import CostService
|
|
6
|
+
from ai_review.services.llm.types import ChatResultSchema
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# ---------- fixtures ----------
|
|
10
|
+
|
|
11
|
+
@pytest.fixture(autouse=True)
|
|
12
|
+
def fake_pricing(monkeypatch: pytest.MonkeyPatch):
|
|
13
|
+
monkeypatch.setattr(
|
|
14
|
+
LLMConfigBase,
|
|
15
|
+
"load_pricing",
|
|
16
|
+
lambda self: {"gpt-4-test": LLMPricingConfig(input=0.000001, output=0.000002)}
|
|
17
|
+
)
|
|
18
|
+
monkeypatch.setattr("ai_review.config.settings.llm.meta.model", "gpt-4-test")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.fixture
|
|
22
|
+
def cost_service() -> CostService:
|
|
23
|
+
return CostService()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def sample_result() -> ChatResultSchema:
|
|
28
|
+
return ChatResultSchema(text="result", prompt_tokens=1000, completion_tokens=500)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ---------- tests: CALCULATE ----------
|
|
32
|
+
|
|
33
|
+
def test_calculate_basic(cost_service: CostService, sample_result: ChatResultSchema) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Should correctly calculate input/output/total cost and return report.
|
|
36
|
+
"""
|
|
37
|
+
report = cost_service.calculate(sample_result)
|
|
38
|
+
|
|
39
|
+
assert isinstance(report, CostReportSchema)
|
|
40
|
+
assert report.model == "gpt-4-test"
|
|
41
|
+
assert pytest.approx(report.input_cost, 1e-8) == 0.001
|
|
42
|
+
assert pytest.approx(report.output_cost, 1e-8) == 0.001
|
|
43
|
+
assert pytest.approx(report.total_cost, 1e-8) == 0.002
|
|
44
|
+
|
|
45
|
+
assert len(cost_service.reports) == 1
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_calculate_missing_tokens(cost_service: CostService) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Should return None if prompt_tokens or completion_tokens is None.
|
|
51
|
+
"""
|
|
52
|
+
result = ChatResultSchema(text="result", prompt_tokens=None, completion_tokens=123)
|
|
53
|
+
assert cost_service.calculate(result) is None
|
|
54
|
+
|
|
55
|
+
result = ChatResultSchema(text="result", prompt_tokens=100, completion_tokens=None)
|
|
56
|
+
assert cost_service.calculate(result) is None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_calculate_no_pricing(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Should return None and log warning if pricing not found.
|
|
62
|
+
"""
|
|
63
|
+
monkeypatch.setattr("ai_review.config.settings.llm.meta.model", "unknown-model")
|
|
64
|
+
monkeypatch.setattr(LLMConfigBase, "load_pricing", lambda self: {})
|
|
65
|
+
|
|
66
|
+
service = CostService()
|
|
67
|
+
result = ChatResultSchema(text="result", prompt_tokens=10, completion_tokens=5)
|
|
68
|
+
out = service.calculate(result)
|
|
69
|
+
|
|
70
|
+
assert out is None
|
|
71
|
+
assert service.reports == []
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# ---------- tests: AGGREGATE ----------
|
|
75
|
+
|
|
76
|
+
def test_aggregate_empty(cost_service: CostService) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Should return None when no reports exist.
|
|
79
|
+
"""
|
|
80
|
+
assert cost_service.aggregate() is None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_aggregate_combines_multiple_reports(cost_service: CostService, sample_result: ChatResultSchema) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Should combine multiple cost reports into a single aggregated summary.
|
|
86
|
+
"""
|
|
87
|
+
cost_service.calculate(sample_result)
|
|
88
|
+
cost_service.calculate(sample_result)
|
|
89
|
+
|
|
90
|
+
agg = cost_service.aggregate()
|
|
91
|
+
assert isinstance(agg, CostReportSchema)
|
|
92
|
+
|
|
93
|
+
assert agg.prompt_tokens == 2000
|
|
94
|
+
assert agg.completion_tokens == 1000
|
|
95
|
+
assert pytest.approx(agg.input_cost, 1e-8) == 0.002
|
|
96
|
+
assert pytest.approx(agg.output_cost, 1e-8) == 0.002
|
|
97
|
+
assert pytest.approx(agg.total_cost, 1e-8) == 0.004
|
|
98
|
+
|
|
99
|
+
assert agg.model == "gpt-4-test"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from ai_review.services.prompt.adapter import build_prompt_context_from_mr_info
|
|
2
|
+
from ai_review.services.vcs.types import (
|
|
3
|
+
ReviewInfoSchema,
|
|
4
|
+
UserSchema,
|
|
5
|
+
BranchRefSchema,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_build_prompt_context_from_full_review_info() -> None:
|
|
10
|
+
review_info = ReviewInfoSchema(
|
|
11
|
+
id=42,
|
|
12
|
+
title="Fix API bug",
|
|
13
|
+
description="Refactored endpoint",
|
|
14
|
+
author=UserSchema(id=1, name="Alice", username="alice"),
|
|
15
|
+
reviewers=[
|
|
16
|
+
UserSchema(id=2, name="Bob", username="bob"),
|
|
17
|
+
UserSchema(id=3, name="Charlie", username="charlie"),
|
|
18
|
+
],
|
|
19
|
+
assignees=[UserSchema(id=4, name="Dave", username="dave")],
|
|
20
|
+
source_branch=BranchRefSchema(ref="feature/fix-api", sha="123abc"),
|
|
21
|
+
target_branch=BranchRefSchema(ref="main", sha="456def"),
|
|
22
|
+
labels=["bug", "backend"],
|
|
23
|
+
changed_files=["api/views.py", "api/tests.py"],
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
context = build_prompt_context_from_mr_info(review_info)
|
|
27
|
+
|
|
28
|
+
assert context.review_title == "Fix API bug"
|
|
29
|
+
assert context.review_description == "Refactored endpoint"
|
|
30
|
+
|
|
31
|
+
assert context.review_author_name == "Alice"
|
|
32
|
+
assert context.review_author_username == "alice"
|
|
33
|
+
|
|
34
|
+
assert context.review_reviewers == ["Bob", "Charlie"]
|
|
35
|
+
assert context.review_reviewers_usernames == ["bob", "charlie"]
|
|
36
|
+
assert context.review_reviewer == "Bob" # первый ревьюер выбран корректно
|
|
37
|
+
|
|
38
|
+
assert context.review_assignees == ["Dave"]
|
|
39
|
+
assert context.review_assignees_usernames == ["dave"]
|
|
40
|
+
|
|
41
|
+
assert context.source_branch == "feature/fix-api"
|
|
42
|
+
assert context.target_branch == "main"
|
|
43
|
+
|
|
44
|
+
assert context.labels == ["bug", "backend"]
|
|
45
|
+
assert context.changed_files == ["api/views.py", "api/tests.py"]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_build_prompt_context_handles_no_reviewers() -> None:
|
|
49
|
+
review_info = ReviewInfoSchema(
|
|
50
|
+
title="Empty reviewers test",
|
|
51
|
+
author=UserSchema(name="Alice", username="alice"),
|
|
52
|
+
reviewers=[],
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
context = build_prompt_context_from_mr_info(review_info)
|
|
56
|
+
|
|
57
|
+
assert context.review_reviewer == ""
|
|
58
|
+
assert context.review_reviewers == []
|
|
59
|
+
assert context.review_reviewers_usernames == []
|
|
@@ -6,24 +6,24 @@ from ai_review.services.prompt.schema import PromptContextSchema
|
|
|
6
6
|
|
|
7
7
|
def test_apply_format_inserts_variables() -> None:
|
|
8
8
|
context = PromptContextSchema(
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
review_title="My Review",
|
|
10
|
+
review_author_username="nikita"
|
|
11
11
|
)
|
|
12
|
-
template = "Title: <<
|
|
12
|
+
template = "Title: <<review_title>>, Author: @<<review_author_username>>"
|
|
13
13
|
result = context.apply_format(template)
|
|
14
|
-
assert result == "Title: My
|
|
14
|
+
assert result == "Title: My Review, Author: @nikita"
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def test_apply_format_with_lists() -> None:
|
|
18
18
|
context = PromptContextSchema(
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
review_reviewers=["Alice", "Bob"],
|
|
20
|
+
review_reviewers_usernames=["alice", "bob"],
|
|
21
21
|
labels=["bug", "feature"],
|
|
22
22
|
changed_files=["a.py", "b.py"],
|
|
23
23
|
)
|
|
24
24
|
template = (
|
|
25
|
-
"Reviewers: <<
|
|
26
|
-
"Usernames: <<
|
|
25
|
+
"Reviewers: <<review_reviewers>>\n"
|
|
26
|
+
"Usernames: <<review_reviewers_usernames>>\n"
|
|
27
27
|
"Labels: <<labels>>\n"
|
|
28
28
|
"Files: <<changed_files>>"
|
|
29
29
|
)
|
|
@@ -36,7 +36,7 @@ def test_apply_format_with_lists() -> None:
|
|
|
36
36
|
|
|
37
37
|
def test_apply_format_handles_missing_fields() -> None:
|
|
38
38
|
context = PromptContextSchema()
|
|
39
|
-
template = "Title: <<
|
|
39
|
+
template = "Title: <<review_title>>, Reviewer: <<review_reviewer>>"
|
|
40
40
|
result = context.apply_format(template)
|
|
41
41
|
assert result == "Title: , Reviewer: "
|
|
42
42
|
|
|
@@ -49,23 +49,23 @@ def test_apply_format_unknown_placeholder_kept() -> None:
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def test_apply_format_multiple_occurrences() -> None:
|
|
52
|
-
context = PromptContextSchema(
|
|
53
|
-
template = "<<
|
|
52
|
+
context = PromptContextSchema(review_title="My Review")
|
|
53
|
+
template = "<<review_title>> again <<review_title>>"
|
|
54
54
|
result = context.apply_format(template)
|
|
55
|
-
assert result == "My
|
|
55
|
+
assert result == "My Review again My Review"
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
def test_apply_format_override_from_settings(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
59
|
-
monkeypatch.setitem(settings.prompt.context, "
|
|
60
|
-
context = PromptContextSchema(
|
|
61
|
-
template = "Title: <<
|
|
59
|
+
monkeypatch.setitem(settings.prompt.context, "review_title", "Overridden")
|
|
60
|
+
context = PromptContextSchema(review_title="Local Value")
|
|
61
|
+
template = "Title: <<review_title>>"
|
|
62
62
|
result = context.apply_format(template)
|
|
63
63
|
assert result == "Title: Overridden"
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
def test_apply_format_prefers_override_even_if_empty(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
67
|
-
monkeypatch.setitem(settings.prompt.context, "
|
|
68
|
-
context = PromptContextSchema(
|
|
69
|
-
template = "Title: <<
|
|
67
|
+
monkeypatch.setitem(settings.prompt.context, "review_title", "")
|
|
68
|
+
context = PromptContextSchema(review_title="Local Value")
|
|
69
|
+
template = "Title: <<review_title>>"
|
|
70
70
|
result = context.apply_format(template)
|
|
71
71
|
assert result == "Title: "
|
|
@@ -20,15 +20,16 @@ def patch_prompts(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
|
20
20
|
|
|
21
21
|
@pytest.fixture
|
|
22
22
|
def dummy_context() -> PromptContextSchema:
|
|
23
|
+
"""Builds a context object that reflects the new unified review schema."""
|
|
23
24
|
return PromptContextSchema(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
review_title="Fix login bug",
|
|
26
|
+
review_description="Some description",
|
|
27
|
+
review_author_name="Nikita",
|
|
28
|
+
review_author_username="nikita.filonov",
|
|
29
|
+
review_reviewers=["Alice", "Bob"],
|
|
30
|
+
review_reviewers_usernames=["alice", "bob"],
|
|
31
|
+
review_assignees=["Charlie"],
|
|
32
|
+
review_assignees_usernames=["charlie"],
|
|
32
33
|
source_branch="feature/login-fix",
|
|
33
34
|
target_branch="main",
|
|
34
35
|
labels=["bug", "critical"],
|
|
@@ -130,16 +131,17 @@ def test_build_system_summary_request_empty(
|
|
|
130
131
|
|
|
131
132
|
|
|
132
133
|
def test_diff_placeholders_are_not_replaced(dummy_context: PromptContextSchema) -> None:
|
|
133
|
-
diffs = [DiffFileSchema(file="x.py", diff='print("<<
|
|
134
|
+
diffs = [DiffFileSchema(file="x.py", diff='print("<<review_title>>")')]
|
|
134
135
|
result = PromptService.build_summary_request(diffs, dummy_context)
|
|
135
136
|
|
|
136
|
-
assert "<<
|
|
137
|
+
assert "<<review_title>>" in result
|
|
137
138
|
assert "Fix login bug" not in result
|
|
138
139
|
|
|
139
140
|
|
|
140
141
|
def test_prepare_prompt_basic_substitution(dummy_context: PromptContextSchema) -> None:
|
|
141
|
-
prompts = ["Hello", "MR title: <<
|
|
142
|
+
prompts = ["Hello", "MR title: <<review_title>>"]
|
|
142
143
|
result = PromptService.prepare_prompt(prompts, dummy_context)
|
|
144
|
+
|
|
143
145
|
assert "Hello" in result
|
|
144
146
|
assert "MR title: Fix login bug" in result
|
|
145
147
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xai-review
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.0
|
|
4
4
|
Summary: AI-powered code review tool
|
|
5
5
|
Author-email: Nikita Filonov <nikita.filonov@example.com>
|
|
6
6
|
Maintainer-email: Nikita Filonov <nikita.filonov@example.com>
|
|
@@ -9,17 +9,26 @@ Project-URL: Issues, https://github.com/Nikita-Filonov/ai-review/issues
|
|
|
9
9
|
Project-URL: Homepage, https://github.com/Nikita-Filonov/ai-review
|
|
10
10
|
Project-URL: Repository, https://github.com/Nikita-Filonov/ai-review
|
|
11
11
|
Keywords: ai,code review,llm,openai,claude,gemini
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
|
+
Classifier: Topic :: Software Development :: Testing
|
|
18
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
12
20
|
Requires-Python: >=3.11
|
|
13
21
|
Description-Content-Type: text/markdown
|
|
14
22
|
License-File: LICENSE
|
|
15
23
|
Requires-Dist: typer
|
|
16
24
|
Requires-Dist: httpx
|
|
17
25
|
Requires-Dist: pyyaml
|
|
18
|
-
Requires-Dist: pytest
|
|
19
26
|
Requires-Dist: loguru
|
|
20
27
|
Requires-Dist: aiofiles
|
|
21
28
|
Requires-Dist: pydantic
|
|
22
29
|
Requires-Dist: pydantic-settings
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest; extra == "test"
|
|
23
32
|
Dynamic: license-file
|
|
24
33
|
|
|
25
34
|
# AI Review
|
|
@@ -76,10 +85,10 @@ mode:
|
|
|
76
85
|
| Mode | Description | Live Example |
|
|
77
86
|
|------------|----------------------------------------------------|-------------------------------------------------------------------------------|
|
|
78
87
|
| 🧩 Inline | Adds line-by-line comments directly in the diff | [Try AI Review (inline)](https://github.com/Nikita-Filonov/ai-review/pull/4) |
|
|
79
|
-
|
|
|
80
|
-
|
|
|
88
|
+
| 🧠 Context | Performs broader analysis across multiple files | [Try AI Review (context)](https://github.com/Nikita-Filonov/ai-review/pull/5) |
|
|
89
|
+
| 📄 Summary | Posts a concise summary review with key highlights | [Try AI Review (summary)](https://github.com/Nikita-Filonov/ai-review/pull/6) |
|
|
81
90
|
|
|
82
|
-
Each review was generated automatically via GitHub Actions using the corresponding mode:
|
|
91
|
+
👉 Each review was generated automatically via GitHub Actions using the corresponding mode:
|
|
83
92
|
|
|
84
93
|
```bash
|
|
85
94
|
ai-review run-inline
|
|
@@ -97,12 +106,18 @@ Install via **pip**:
|
|
|
97
106
|
pip install xai-review
|
|
98
107
|
```
|
|
99
108
|
|
|
109
|
+
📦 Available on [PyPI](https://pypi.org/project/xai-review/)
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
100
113
|
Or run directly via Docker:
|
|
101
114
|
|
|
102
115
|
```bash
|
|
103
116
|
docker run --rm -v $(pwd):/app nikitafilonov/ai-review:latest run-summary
|
|
104
117
|
```
|
|
105
118
|
|
|
119
|
+
🐳 Pull from [DockerHub](https://hub.docker.com/r/nikitafilonov/ai-review)
|
|
120
|
+
|
|
106
121
|
👉 Before running, create a basic configuration file [.ai-review.yaml](./docs/configs/.ai-review.yaml) in the root of
|
|
107
122
|
your project:
|
|
108
123
|
|
|
@@ -192,7 +207,7 @@ jobs:
|
|
|
192
207
|
runs-on: ubuntu-latest
|
|
193
208
|
steps:
|
|
194
209
|
- uses: actions/checkout@v4
|
|
195
|
-
- uses: Nikita-Filonov/ai-review@v0.
|
|
210
|
+
- uses: Nikita-Filonov/ai-review@v0.19.0
|
|
196
211
|
with:
|
|
197
212
|
review-command: ${{ inputs.review-command }}
|
|
198
213
|
env:
|
|
@@ -17,20 +17,20 @@ ai_review/clients/gemini/schema.py,sha256=5oVvbI-h_sw8bFreS4JUmMj-aXa_frvxK3H8sg
|
|
|
17
17
|
ai_review/clients/github/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
18
|
ai_review/clients/github/client.py,sha256=4uZsnMY-OZ9BNzMLqEHG80jgpyQdd61ePNdVuwGMcrI,1134
|
|
19
19
|
ai_review/clients/github/pr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
ai_review/clients/github/pr/client.py,sha256=
|
|
20
|
+
ai_review/clients/github/pr/client.py,sha256=sANW1K2MomgHzH4beqkkfHaEY2sRxiAVCDXjspOmcHA,5402
|
|
21
21
|
ai_review/clients/github/pr/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
ai_review/clients/github/pr/schema/comments.py,sha256=K9KQ9TmWv9Hjw8uTrCPkzyAVbFohjCCf_rww6Ucj3wM,650
|
|
23
23
|
ai_review/clients/github/pr/schema/files.py,sha256=mLHg1CfXUKCdQf5YUtuJ8n6xOROKoAjiJY5PL70kP-w,269
|
|
24
|
-
ai_review/clients/github/pr/schema/pull_request.py,sha256=
|
|
24
|
+
ai_review/clients/github/pr/schema/pull_request.py,sha256=EwOworYQY4kCmL6QFKEXK7r2fpINK8o-4-FEy9-nTpg,688
|
|
25
25
|
ai_review/clients/github/pr/schema/reviews.py,sha256=v99DLYT5LOAcc18PATIse1mld8J0wKEAaTzUKI70s0c,288
|
|
26
26
|
ai_review/clients/gitlab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
27
|
ai_review/clients/gitlab/client.py,sha256=acMflkHGp8mv0TVLdZ1gmdXkWQPcq609QjmkYWjEmys,1136
|
|
28
28
|
ai_review/clients/gitlab/mr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
ai_review/clients/gitlab/mr/client.py,sha256
|
|
29
|
+
ai_review/clients/gitlab/mr/client.py,sha256=IeLq4-aL6k9-4W_-bhCwsujKSUvT68oBB6YlgSsS_VQ,4522
|
|
30
30
|
ai_review/clients/gitlab/mr/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
ai_review/clients/gitlab/mr/schema/changes.py,sha256=
|
|
32
|
-
ai_review/clients/gitlab/mr/schema/
|
|
33
|
-
ai_review/clients/gitlab/mr/schema/
|
|
31
|
+
ai_review/clients/gitlab/mr/schema/changes.py,sha256=ZqSPb8zO0z_V8cEjxoTqnwbjRLxo6OTV4LeQEAg91cU,835
|
|
32
|
+
ai_review/clients/gitlab/mr/schema/discussions.py,sha256=DZqZTpLErmwSEsYSp6-XeBUo1kmFj3q6Zn_f3b6N9kk,718
|
|
33
|
+
ai_review/clients/gitlab/mr/schema/notes.py,sha256=Vm-OZ9z34h57FtzazSQSZ5ZFnq6Sw568zG3R99TQTzI,358
|
|
34
34
|
ai_review/clients/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
35
|
ai_review/clients/openai/client.py,sha256=N07ZRnbptOtab8imMUZbGL-kRoOwIZmNYbHySumD3IU,1707
|
|
36
36
|
ai_review/clients/openai/schema.py,sha256=glxwMtBrDA6W0BQgH-ruKe0bKH3Ps1P-Y1-2jGdqaUM,764
|
|
@@ -97,7 +97,7 @@ ai_review/services/git/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
97
97
|
ai_review/services/git/service.py,sha256=_RMwgcllDoSLUzl84JML38fWkr7swnkUr6MJ46hSkWw,1282
|
|
98
98
|
ai_review/services/git/types.py,sha256=QTOCTmR-Rt3sUjzZQHu2PGo_6un5gvNupifAa84wON4,413
|
|
99
99
|
ai_review/services/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
100
|
-
ai_review/services/llm/factory.py,sha256=
|
|
100
|
+
ai_review/services/llm/factory.py,sha256=fOyxSznQFdVuJQVilqtc0puWNoHCxZ5cdwtxRVfqTHw,725
|
|
101
101
|
ai_review/services/llm/types.py,sha256=zMcMFQ7F9Zcgc9JqwdHCdlTpGOA0HuWyGgoySsUh4_o,345
|
|
102
102
|
ai_review/services/llm/claude/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
103
103
|
ai_review/services/llm/claude/client.py,sha256=w6CvfDYEAKyi_r88M-z_jCvMIJF3SjhQjV1EHMvNh24,1066
|
|
@@ -106,12 +106,12 @@ ai_review/services/llm/gemini/client.py,sha256=7FAOlTi8rV6b8g8aWcg-0LIP77AtbAoPt
|
|
|
106
106
|
ai_review/services/llm/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
107
|
ai_review/services/llm/openai/client.py,sha256=WhMXNfH_G1NTlFkdRK5sgYvrCIE5ZQNfPhdYx49IXFk,1143
|
|
108
108
|
ai_review/services/prompt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
109
|
-
ai_review/services/prompt/adapter.py,sha256=
|
|
110
|
-
ai_review/services/prompt/schema.py,sha256=
|
|
109
|
+
ai_review/services/prompt/adapter.py,sha256=YgD8Cf73pwPOnKxq9QSlbYr8wySfDxJE_3fIrRWfkUo,984
|
|
110
|
+
ai_review/services/prompt/schema.py,sha256=x-1KRFOK3HdZozXJNPh-Bp_JrZ2AIdAPD44lhWG5g9k,1863
|
|
111
111
|
ai_review/services/prompt/service.py,sha256=D1PR2HC4cgrEND6mAhU5EPRAtp4mgEkOLEyD51WBc0g,2129
|
|
112
112
|
ai_review/services/prompt/tools.py,sha256=-gS74mVM3OZPKWQkY9_QfStkfxaUfssDbJ3Bdi4AQ74,636
|
|
113
113
|
ai_review/services/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
114
|
-
ai_review/services/review/service.py,sha256=
|
|
114
|
+
ai_review/services/review/service.py,sha256=sYJQ02bKKQ926FpSmsHeeKfmRM1oMIqwjOFdKY88mws,8532
|
|
115
115
|
ai_review/services/review/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
116
116
|
ai_review/services/review/inline/schema.py,sha256=ry8sJdTgusQvFW51neRiapzgzVGwswwJzdYhaV3hbT0,1545
|
|
117
117
|
ai_review/services/review/inline/service.py,sha256=34I3eK2Ra1l3aUvSYfO-Wx9aPfcgCWqTgjdoGHlNO08,2135
|
|
@@ -121,12 +121,12 @@ ai_review/services/review/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
|
|
|
121
121
|
ai_review/services/review/summary/schema.py,sha256=GipVNWrEKtgZPkytNSrXwzvX9Zq8Pv2wxjXhfJq4D3g,364
|
|
122
122
|
ai_review/services/review/summary/service.py,sha256=GB7-l4UyjZfUe6yP_8Q-SD1_uDKHM0W-CZJVMiEL8S0,449
|
|
123
123
|
ai_review/services/vcs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
124
|
-
ai_review/services/vcs/factory.py,sha256=
|
|
125
|
-
ai_review/services/vcs/types.py,sha256=
|
|
124
|
+
ai_review/services/vcs/factory.py,sha256=PSjBUClHRw0_38XmBYZBGIs281NMHX-vVzBwhnEn9uo,590
|
|
125
|
+
ai_review/services/vcs/types.py,sha256=ErKrALHyn7qdIg1_wZ5Af-A60HUotKHunZhIvC2GRKM,1990
|
|
126
126
|
ai_review/services/vcs/github/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
127
|
-
ai_review/services/vcs/github/client.py,sha256=
|
|
127
|
+
ai_review/services/vcs/github/client.py,sha256=Pv18vGSjcXoapTsiLqKoEUZlv2ua7pp01IBRgxpAmM8,6301
|
|
128
128
|
ai_review/services/vcs/gitlab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
129
|
-
ai_review/services/vcs/gitlab/client.py,sha256
|
|
129
|
+
ai_review/services/vcs/gitlab/client.py,sha256=y1X99RVgA1KRcr_dW8gNaHuoSqxK1-30hzeIZA4HkhA,6678
|
|
130
130
|
ai_review/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
131
131
|
ai_review/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
132
132
|
ai_review/tests/fixtures/git.py,sha256=CwMYAQNVEeHp8OCnFWh2fBKkBkyorWJtN2eDFqpYRbQ,1038
|
|
@@ -156,13 +156,17 @@ ai_review/tests/suites/libs/diff/test_tools.py,sha256=XkHJZ-b5veFz5oLKO09P7npaLN
|
|
|
156
156
|
ai_review/tests/suites/libs/template/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
157
157
|
ai_review/tests/suites/libs/template/test_render.py,sha256=n-ss5bd_hwc-RzYmqWmFM6KSlP1zLSnlsW1Yki12Bpw,1890
|
|
158
158
|
ai_review/tests/suites/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
159
|
+
ai_review/tests/suites/services/cost/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
160
|
+
ai_review/tests/suites/services/cost/test_schema.py,sha256=AI3Wg1sR6nzLpkEqJGDu6nDYwiwzbbghsxhRNwRsUFA,3044
|
|
161
|
+
ai_review/tests/suites/services/cost/test_service.py,sha256=fMW4Tg6BRMXKcqOO7MmSqJc1mpuguvFSl0GjS93m7u8,3253
|
|
159
162
|
ai_review/tests/suites/services/diff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
160
163
|
ai_review/tests/suites/services/diff/test_renderers.py,sha256=IKOpsGedONNW8ZfYTAk0Vq0hfFi7L6TpWs8vVVQroj0,6273
|
|
161
164
|
ai_review/tests/suites/services/diff/test_service.py,sha256=iFkGX9Vj2X44JU3eFsoHsg9o9353eKX-QCv_J9KxfzU,3162
|
|
162
165
|
ai_review/tests/suites/services/diff/test_tools.py,sha256=HBQ3eCn-kLeb_k5iTgyr09x0VwLYSegSbxm0Qk9ZrCc,3543
|
|
163
166
|
ai_review/tests/suites/services/prompt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
164
|
-
ai_review/tests/suites/services/prompt/
|
|
165
|
-
ai_review/tests/suites/services/prompt/
|
|
167
|
+
ai_review/tests/suites/services/prompt/test_adapter.py,sha256=9KZOFQmZUs3l_cW7Q5LIMPs4i4J-gOCQ6VrlDPR0ImU,2156
|
|
168
|
+
ai_review/tests/suites/services/prompt/test_schema.py,sha256=DQyv5gUJ2VkxaD9wiKLS18ECopvvdKvF4sg3MTGcKs8,2547
|
|
169
|
+
ai_review/tests/suites/services/prompt/test_service.py,sha256=WXYKwDHMmWD6ew1awiEzmoxEJtQBqxvOgiyK8Ii9Mhw,6755
|
|
166
170
|
ai_review/tests/suites/services/prompt/test_tools.py,sha256=_yNZoBATvPU5enWNIopbjY8lVVjfaB_46kNIKODhCW4,1981
|
|
167
171
|
ai_review/tests/suites/services/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
168
172
|
ai_review/tests/suites/services/review/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -173,9 +177,9 @@ ai_review/tests/suites/services/review/policy/test_service.py,sha256=kRWT550OjWY
|
|
|
173
177
|
ai_review/tests/suites/services/review/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
174
178
|
ai_review/tests/suites/services/review/summary/test_schema.py,sha256=xSoydvABZldHaVDa0OBFvYrj8wMuZqUDN3MO-XdvxOI,819
|
|
175
179
|
ai_review/tests/suites/services/review/summary/test_service.py,sha256=8UMvi_NL9frm280vD6Q1NCDrdI7K8YbXzoViIus-I2g,541
|
|
176
|
-
xai_review-0.
|
|
177
|
-
xai_review-0.
|
|
178
|
-
xai_review-0.
|
|
179
|
-
xai_review-0.
|
|
180
|
-
xai_review-0.
|
|
181
|
-
xai_review-0.
|
|
180
|
+
xai_review-0.19.0.dist-info/licenses/LICENSE,sha256=p-v8m7Kmz4KKc7PcvsGiGEmCw9AiSXY4_ylOPy_u--Y,11343
|
|
181
|
+
xai_review-0.19.0.dist-info/METADATA,sha256=iaEYvCCq2eaoDSteH4tuHdBbq4j5Id_dRGZboXbnyPw,10409
|
|
182
|
+
xai_review-0.19.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
183
|
+
xai_review-0.19.0.dist-info/entry_points.txt,sha256=JyC5URanMi5io5P_PXQf7H_I1OGIpk5cZQhaPQ0g4Zs,53
|
|
184
|
+
xai_review-0.19.0.dist-info/top_level.txt,sha256=sTsZbfzLoqvRZKdKa-BcxWvjlHdrpbeJ6DrGY0EuR0E,10
|
|
185
|
+
xai_review-0.19.0.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from pydantic import BaseModel, RootModel
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class GitLabMRCommentSchema(BaseModel):
|
|
5
|
-
id: int
|
|
6
|
-
body: str
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class GitLabGetMRCommentsResponseSchema(RootModel[list[GitLabMRCommentSchema]]):
|
|
10
|
-
root: list[GitLabMRCommentSchema]
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class GitLabCreateMRCommentRequestSchema(BaseModel):
|
|
14
|
-
body: str
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class GitLabCreateMRCommentResponseSchema(BaseModel):
|
|
18
|
-
id: int
|
|
19
|
-
body: str
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|