xai-review 0.10.0__py3-none-any.whl → 0.12.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.

@@ -8,6 +8,7 @@ from ai_review.libs.resources import load_resource
8
8
 
9
9
  class PromptConfig(BaseModel):
10
10
  context: dict[str, str] = Field(default_factory=dict)
11
+ normalize_prompts: bool = True
11
12
  context_placeholder: str = "<<{value}>>"
12
13
  inline_prompt_files: list[FilePath] | None = None
13
14
  context_prompt_files: list[FilePath] | None = None
ai_review/libs/json.py CHANGED
@@ -1,19 +1,16 @@
1
1
  import re
2
2
 
3
3
  CONTROL_CHARS_RE = re.compile(r"[\x00-\x1F]")
4
+ REPLACEMENTS = {
5
+ "\n": "\\n",
6
+ "\r": "\\r",
7
+ "\t": "\\t",
8
+ }
4
9
 
5
10
 
6
11
  def sanitize_json_string(raw: str) -> str:
7
12
  def replace(match: re.Match) -> str:
8
13
  char = match.group()
9
- match char:
10
- case "\n":
11
- return "\\n"
12
- case "\r":
13
- return "\\r"
14
- case "\t":
15
- return "\\t"
16
- case _:
17
- return f"\\u{ord(char):04x}"
14
+ return REPLACEMENTS.get(char, f"\\u{ord(char):04x}")
18
15
 
19
16
  return CONTROL_CHARS_RE.sub(replace, raw)
@@ -1,56 +1,57 @@
1
1
  from ai_review.config import settings
2
2
  from ai_review.services.diff.schema import DiffFileSchema
3
3
  from ai_review.services.prompt.schema import PromptContextSchema
4
+ from ai_review.services.prompt.tools import normalize_prompt, format_file
4
5
 
5
6
 
6
- def format_file(diff: DiffFileSchema) -> str:
7
- return f"# File: {diff.file}\n{diff.diff}\n"
7
+ class PromptService:
8
+ @classmethod
9
+ def prepare_prompt(cls, prompts: list[str], context: PromptContextSchema) -> str:
10
+ prompt = "\n\n".join(prompts)
11
+ prompt = context.apply_format(prompt)
8
12
 
13
+ if settings.prompt.normalize_prompts:
14
+ prompt = normalize_prompt(prompt)
15
+
16
+ return prompt
9
17
 
10
- class PromptService:
11
18
  @classmethod
12
19
  def build_inline_request(cls, diff: DiffFileSchema, context: PromptContextSchema) -> str:
13
- inline_prompts = "\n\n".join(settings.prompt.load_inline())
14
- inline_prompts = context.apply_format(inline_prompts)
20
+ prompt = cls.prepare_prompt(settings.prompt.load_inline(), context)
15
21
  return (
16
- f"{inline_prompts}\n\n"
22
+ f"{prompt}\n\n"
17
23
  f"## Diff\n\n"
18
24
  f"{format_file(diff)}"
19
25
  )
20
26
 
21
27
  @classmethod
22
28
  def build_summary_request(cls, diffs: list[DiffFileSchema], context: PromptContextSchema) -> str:
29
+ prompt = cls.prepare_prompt(settings.prompt.load_summary(), context)
23
30
  changes = "\n\n".join(map(format_file, diffs))
24
- summary_prompts = "\n\n".join(settings.prompt.load_summary())
25
- summary_prompts = context.apply_format(summary_prompts)
26
31
  return (
27
- f"{summary_prompts}\n\n"
32
+ f"{prompt}\n\n"
28
33
  f"## Changes\n\n"
29
34
  f"{changes}\n"
30
35
  )
31
36
 
32
37
  @classmethod
33
38
  def build_context_request(cls, diffs: list[DiffFileSchema], context: PromptContextSchema) -> str:
39
+ prompt = cls.prepare_prompt(settings.prompt.load_context(), context)
34
40
  changes = "\n\n".join(map(format_file, diffs))
35
- inline_prompts = "\n\n".join(settings.prompt.load_context())
36
- inline_prompts = context.apply_format(inline_prompts)
37
41
  return (
38
- f"{inline_prompts}\n\n"
42
+ f"{prompt}\n\n"
39
43
  f"## Diff\n\n"
40
44
  f"{changes}\n"
41
45
  )
42
46
 
43
47
  @classmethod
44
48
  def build_system_inline_request(cls, context: PromptContextSchema) -> str:
45
- prompt = "\n\n".join(settings.prompt.load_system_inline())
46
- return context.apply_format(prompt)
49
+ return cls.prepare_prompt(settings.prompt.load_system_inline(), context)
47
50
 
48
51
  @classmethod
49
52
  def build_system_context_request(cls, context: PromptContextSchema) -> str:
50
- prompt = "\n\n".join(settings.prompt.load_system_context())
51
- return context.apply_format(prompt)
53
+ return cls.prepare_prompt(settings.prompt.load_system_context(), context)
52
54
 
53
55
  @classmethod
54
56
  def build_system_summary_request(cls, context: PromptContextSchema) -> str:
55
- prompt = "\n\n".join(settings.prompt.load_system_summary())
56
- return context.apply_format(prompt)
57
+ return cls.prepare_prompt(settings.prompt.load_system_summary(), context)
@@ -0,0 +1,24 @@
1
+ import re
2
+
3
+ from ai_review.libs.logger import get_logger
4
+ from ai_review.services.diff.schema import DiffFileSchema
5
+
6
+ logger = get_logger("PROMPT_TOOLS")
7
+
8
+
9
+ def format_file(diff: DiffFileSchema) -> str:
10
+ return f"# File: {diff.file}\n{diff.diff}\n"
11
+
12
+
13
+ def normalize_prompt(text: str) -> str:
14
+ tails_stripped = [re.sub(r"[ \t]+$", "", line) for line in text.splitlines()]
15
+ text = "\n".join(tails_stripped)
16
+
17
+ text = re.sub(r"\n{3,}", "\n\n", text)
18
+
19
+ result = text.strip()
20
+ if len(text) > len(result):
21
+ logger.info(f"Prompt has been normalized from {len(text)} to {len(result)}")
22
+ return result
23
+
24
+ return text
@@ -18,12 +18,12 @@ class InlineCommentService:
18
18
  try:
19
19
  return InlineCommentListSchema.model_validate_json(raw)
20
20
  except ValidationError as error:
21
- logger.debug(f"Parse failed, trying sanitized JSON: {raw[:200]=}, {error=}")
21
+ logger.warning(f"Parse failed, trying sanitized JSON: {raw[:200]=}, {error=}")
22
22
  try:
23
23
  cleaned = sanitize_json_string(raw)
24
24
  return InlineCommentListSchema.model_validate_json(cleaned)
25
25
  except ValidationError as error:
26
- logger.debug(f"Sanitized JSON still invalid: {raw[:200]=}, {error=}")
26
+ logger.warning(f"Sanitized JSON still invalid: {raw[:200]=}, {error=}")
27
27
  return None
28
28
 
29
29
  @classmethod
@@ -12,30 +12,16 @@ from ai_review.libs.json import sanitize_json_string
12
12
  ("a\tb", "a\\tb"),
13
13
  ("abc\0def", "abc\\u0000def"),
14
14
  ("x\n\ry\t\0z", "x\\n\\ry\\t\\u0000z"),
15
+ ("\n\r\t\0", "\\n\\r\\t\\u0000"),
16
+ ("", "")
15
17
  ],
16
18
  )
17
19
  def test_sanitize_basic_cases(actual: str, expected: str) -> None:
18
20
  assert sanitize_json_string(actual) == expected
19
21
 
20
22
 
21
- def test_sanitize_multiple_control_chars() -> None:
22
- raw = "A\nB\rC\tD\0E"
23
- result = sanitize_json_string(raw)
24
- assert result == "A\\nB\\rC\\tD\\u0000E"
25
-
26
-
27
23
  def test_sanitize_idempotent() -> None:
28
24
  raw = "foo\nbar"
29
25
  once = sanitize_json_string(raw)
30
26
  twice = sanitize_json_string(once)
31
27
  assert once == twice
32
-
33
-
34
- def test_sanitize_empty_string() -> None:
35
- assert sanitize_json_string("") == ""
36
-
37
-
38
- def test_sanitize_only_control_chars() -> None:
39
- raw = "\n\r\t\0"
40
- result = sanitize_json_string(raw)
41
- assert result == "\\n\\r\\t\\u0000"
@@ -1,5 +1,6 @@
1
1
  import pytest
2
2
 
3
+ from ai_review.config import settings
3
4
  from ai_review.libs.config.prompt import PromptConfig
4
5
  from ai_review.services.diff.schema import DiffFileSchema
5
6
  from ai_review.services.prompt.schema import PromptContextSchema
@@ -134,3 +135,35 @@ def test_diff_placeholders_are_not_replaced(dummy_context: PromptContextSchema)
134
135
 
135
136
  assert "<<merge_request_title>>" in result
136
137
  assert "Fix login bug" not in result
138
+
139
+
140
+ def test_prepare_prompt_basic_substitution(dummy_context: PromptContextSchema) -> None:
141
+ prompts = ["Hello", "MR title: <<merge_request_title>>"]
142
+ result = PromptService.prepare_prompt(prompts, dummy_context)
143
+ assert "Hello" in result
144
+ assert "MR title: Fix login bug" in result
145
+
146
+
147
+ def test_prepare_prompt_applies_normalization(
148
+ monkeypatch: pytest.MonkeyPatch,
149
+ dummy_context: PromptContextSchema
150
+ ) -> None:
151
+ monkeypatch.setattr(settings.prompt, "normalize_prompts", True)
152
+ prompts = ["Line with space ", "", "", "Next line"]
153
+ result = PromptService.prepare_prompt(prompts, dummy_context)
154
+
155
+ assert "Line with space" in result
156
+ assert "Next line" in result
157
+ assert "\n\n\n" not in result
158
+
159
+
160
+ def test_prepare_prompt_skips_normalization(
161
+ monkeypatch: pytest.MonkeyPatch,
162
+ dummy_context: PromptContextSchema
163
+ ) -> None:
164
+ monkeypatch.setattr(settings.prompt, "normalize_prompts", False)
165
+ prompts = ["Line with space ", "", "", "Next line"]
166
+ result = PromptService.prepare_prompt(prompts, dummy_context)
167
+
168
+ assert "Line with space " in result
169
+ assert "\n\n\n" in result
@@ -0,0 +1,72 @@
1
+ from ai_review.services.diff.schema import DiffFileSchema
2
+ from ai_review.services.prompt.tools import format_file, normalize_prompt
3
+
4
+
5
+ def test_format_file_basic():
6
+ diff = DiffFileSchema(file="main.py", diff="+ print('hello')")
7
+ result = format_file(diff)
8
+ assert result == "# File: main.py\n+ print('hello')\n"
9
+
10
+
11
+ def test_format_file_empty_diff():
12
+ diff = DiffFileSchema(file="empty.py", diff="")
13
+ result = format_file(diff)
14
+ assert result == "# File: empty.py\n\n"
15
+
16
+
17
+ def test_format_file_multiline_diff():
18
+ diff = DiffFileSchema(
19
+ file="utils/helpers.py",
20
+ diff="- old line\n+ new line\n+ another line"
21
+ )
22
+ result = format_file(diff)
23
+ expected = (
24
+ "# File: utils/helpers.py\n"
25
+ "- old line\n"
26
+ "+ new line\n"
27
+ "+ another line\n"
28
+ )
29
+ assert result == expected
30
+
31
+
32
+ def test_format_file_filename_with_path():
33
+ diff = DiffFileSchema(file="src/app/models/user.py", diff="+ class User:")
34
+ result = format_file(diff)
35
+ assert result.startswith("# File: src/app/models/user.py\n")
36
+ assert result.endswith("+ class User:\n")
37
+
38
+
39
+ def test_trailing_spaces_are_removed():
40
+ text = "hello \nworld\t\t"
41
+ result = normalize_prompt(text)
42
+ assert result == "hello\nworld"
43
+
44
+
45
+ def test_multiple_empty_lines_collapsed():
46
+ text = "line1\n\n\n\nline2"
47
+ result = normalize_prompt(text)
48
+ assert result == "line1\n\nline2"
49
+
50
+
51
+ def test_leading_and_trailing_whitespace_removed():
52
+ text = "\n\n hello\nworld \n\n"
53
+ result = normalize_prompt(text)
54
+ assert result == "hello\nworld"
55
+
56
+
57
+ def test_internal_spaces_preserved():
58
+ text = "foo bar\nbaz\t\tqux"
59
+ result = normalize_prompt(text)
60
+ assert result == "foo bar\nbaz\t\tqux"
61
+
62
+
63
+ def test_only_whitespace_string():
64
+ text = " \n \n"
65
+ result = normalize_prompt(text)
66
+ assert result == ""
67
+
68
+
69
+ def test_no_changes_when_already_clean():
70
+ text = "line1\nline2"
71
+ result = normalize_prompt(text)
72
+ assert result == text
@@ -53,6 +53,8 @@ def test_json_with_raw_newline_sanitized():
53
53
  output = '[{"file": "e.py", "line": 3, "message": "line1\nline2"}]'
54
54
  result = InlineCommentService.parse_model_output(output)
55
55
  assert len(result.root) == 1
56
+ assert result.root[0].file == "e.py"
57
+ assert result.root[0].line == 3
56
58
  assert result.root[0].message == "line1\nline2"
57
59
 
58
60
 
@@ -85,6 +87,8 @@ def test_try_parse_valid_json():
85
87
  assert isinstance(result, InlineCommentListSchema)
86
88
  assert len(result.root) == 1
87
89
  assert result.root[0].file == "ok.py"
90
+ assert result.root[0].line == 1
91
+ assert result.root[0].message == "all good"
88
92
 
89
93
 
90
94
  def test_try_parse_needs_sanitization():
@@ -92,6 +96,8 @@ def test_try_parse_needs_sanitization():
92
96
  result = InlineCommentService.try_parse_model_output(raw)
93
97
  assert result is not None
94
98
  assert result.root[0].file == "bad.py"
99
+ assert result.root[0].line == 2
100
+ assert result.root[0].message == "line1\nline2"
95
101
  assert "line1" in result.root[0].message
96
102
 
97
103
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xai-review
3
- Version: 0.10.0
3
+ Version: 0.12.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>
@@ -26,7 +26,7 @@ ai_review/clients/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
26
26
  ai_review/clients/openai/client.py,sha256=N07ZRnbptOtab8imMUZbGL-kRoOwIZmNYbHySumD3IU,1707
27
27
  ai_review/clients/openai/schema.py,sha256=glxwMtBrDA6W0BQgH-ruKe0bKH3Ps1P-Y1-2jGdqaUM,764
28
28
  ai_review/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- ai_review/libs/json.py,sha256=koGnjcPgHBq3DHvzr090pM1ZCPtM9TjAoqWhnZJIo1I,460
29
+ ai_review/libs/json.py,sha256=g-P5_pNUomQ-bGHCXASvPKj9Og0s9MaLFVEAkzqGp1A,350
30
30
  ai_review/libs/logger.py,sha256=LbXR2Zk1btJ-83I-vHee7cUETgT1mHToSsqEI_8uM0U,370
31
31
  ai_review/libs/resources.py,sha256=s9taAbL1Shl_GiGkPpkkivUcM1Yh6d_IQAG97gffsJU,748
32
32
  ai_review/libs/asynchronous/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -41,7 +41,7 @@ ai_review/libs/config/http.py,sha256=QsIj0yH1IYELOFBQ5AoqPZT0kGIIrQ19cxk1ozPRhLE
41
41
  ai_review/libs/config/llm.py,sha256=cK-e4NCQxnnixLATCsO8-r5k3zUWz1N0BdPCoqerORM,1824
42
42
  ai_review/libs/config/logger.py,sha256=oPmjpjf6EZwW7CgOjT8mOQdGnT98CLwXepiGB_ajZvU,384
43
43
  ai_review/libs/config/openai.py,sha256=vOYqhUq0ceEuNdQrQaHq44lVS5M648mB61Zc4YlfJVw,271
44
- ai_review/libs/config/prompt.py,sha256=e5jmHsfC6WpnkYZpTLT9TyKQfGtsbqJbxMkJBmLAWf0,4434
44
+ ai_review/libs/config/prompt.py,sha256=8aO5WNnhVhQcpWzWxqzb9lq6PzormaJazVwPHuf_ia8,4469
45
45
  ai_review/libs/config/review.py,sha256=LEZni68iH_0m4URPfN0d3F6yrrK7KSn-BwXf-7w2al8,1058
46
46
  ai_review/libs/config/vcs.py,sha256=FduvJJkGObh2LgTSapaMB6FABIvjX7E63yTwZF4p8CU,517
47
47
  ai_review/libs/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -98,12 +98,13 @@ ai_review/services/llm/openai/client.py,sha256=WhMXNfH_G1NTlFkdRK5sgYvrCIE5ZQNfP
98
98
  ai_review/services/prompt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
99
  ai_review/services/prompt/adapter.py,sha256=humGHLRVBu0JspeULgYHCs782BAy4YYKSf5yaG8aF24,1003
100
100
  ai_review/services/prompt/schema.py,sha256=erAecUYzOWyZfixt-pjmPSnvcMDh5DajMd1b7_SPm_o,2052
101
- ai_review/services/prompt/service.py,sha256=VsY8mj6UvY1a4Zsb8JlDJIg_8l7LBW6PXrObiHCwCzo,2128
101
+ ai_review/services/prompt/service.py,sha256=D1PR2HC4cgrEND6mAhU5EPRAtp4mgEkOLEyD51WBc0g,2129
102
+ ai_review/services/prompt/tools.py,sha256=-gS74mVM3OZPKWQkY9_QfStkfxaUfssDbJ3Bdi4AQ74,636
102
103
  ai_review/services/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
104
  ai_review/services/review/service.py,sha256=8YhRFqhZAk2pAnkDaytKSCENlOeOti1brAJq3R9tVMY,8394
104
105
  ai_review/services/review/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
106
  ai_review/services/review/inline/schema.py,sha256=ry8sJdTgusQvFW51neRiapzgzVGwswwJzdYhaV3hbT0,1545
106
- ai_review/services/review/inline/service.py,sha256=qJqtjLY1En07_ZiI_wnhJHZDFfUSUHDqkMXutd1ZuMc,2131
107
+ ai_review/services/review/inline/service.py,sha256=34I3eK2Ra1l3aUvSYfO-Wx9aPfcgCWqTgjdoGHlNO08,2135
107
108
  ai_review/services/review/policy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
108
109
  ai_review/services/review/policy/service.py,sha256=yGDePLxAEF3N1Pkh47jGVd-4dGEESyxDXIXxV7KQfuY,2027
109
110
  ai_review/services/review/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -131,7 +132,7 @@ ai_review/tests/suites/clients/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCe
131
132
  ai_review/tests/suites/clients/openai/test_client.py,sha256=Ox5ifP1C_gSeDRacBa9DnXhe__Z8-WcbzR2JH_V3xKo,1050
132
133
  ai_review/tests/suites/clients/openai/test_schema.py,sha256=x1tamS4GC9pOTpjieKDbK2D73CVV4BkATppytwMevLo,1599
133
134
  ai_review/tests/suites/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
134
- ai_review/tests/suites/libs/test_json.py,sha256=vmbkzRRyPuP-0uyLLlj-Tf_0MAWI_V2wDev9sM8tAHw,1054
135
+ ai_review/tests/suites/libs/test_json.py,sha256=q_tvFcL9EaN5jr48Ed_mxMEmW6xXS0xlZGqSooPZBa4,713
135
136
  ai_review/tests/suites/libs/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
137
  ai_review/tests/suites/libs/config/test_prompt.py,sha256=kDMTnykC54tTPfE6cqYRBbV8d5jzAKucXdJfwtqUybM,2242
137
138
  ai_review/tests/suites/libs/diff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -147,19 +148,20 @@ ai_review/tests/suites/services/diff/test_service.py,sha256=iFkGX9Vj2X44JU3eFsoH
147
148
  ai_review/tests/suites/services/diff/test_tools.py,sha256=HBQ3eCn-kLeb_k5iTgyr09x0VwLYSegSbxm0Qk9ZrCc,3543
148
149
  ai_review/tests/suites/services/prompt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
150
  ai_review/tests/suites/services/prompt/test_schema.py,sha256=XkJk4N9ovgod7G3i6oZwRBjpd71sv0vtVDJhSOfIwGA,2660
150
- ai_review/tests/suites/services/prompt/test_service.py,sha256=M8vvBhEbyHnXCSiIRu7231odn89sPDyCiRMOc2XufC4,5570
151
+ ai_review/tests/suites/services/prompt/test_service.py,sha256=plJ8xDnBifCrLtHJO00cdl11U1EsqSw7lBrEGxu0AIw,6752
152
+ ai_review/tests/suites/services/prompt/test_tools.py,sha256=_yNZoBATvPU5enWNIopbjY8lVVjfaB_46kNIKODhCW4,1981
151
153
  ai_review/tests/suites/services/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
152
154
  ai_review/tests/suites/services/review/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
155
  ai_review/tests/suites/services/review/inline/test_schema.py,sha256=tIz-1UA_GgwcdsyUqgrodiiVVmd_jhoOVmtEwzRVWiY,2474
154
- ai_review/tests/suites/services/review/inline/test_service.py,sha256=ZcrEWKyD-Fsu3tqAOzT1Et1bxLbX6Hn0_Jc9xE_1_78,3566
156
+ ai_review/tests/suites/services/review/inline/test_service.py,sha256=x8d-dhw_uEXtGVLDVv4xVodmscrXIfDkoAnG4UapdlQ,3815
155
157
  ai_review/tests/suites/services/review/policy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
158
  ai_review/tests/suites/services/review/policy/test_service.py,sha256=kRWT550OjWYQ7ZfsihBRc-tx-NMkhlynEsqur55RK0M,3687
157
159
  ai_review/tests/suites/services/review/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
158
160
  ai_review/tests/suites/services/review/summary/test_schema.py,sha256=xSoydvABZldHaVDa0OBFvYrj8wMuZqUDN3MO-XdvxOI,819
159
161
  ai_review/tests/suites/services/review/summary/test_service.py,sha256=8UMvi_NL9frm280vD6Q1NCDrdI7K8YbXzoViIus-I2g,541
160
- xai_review-0.10.0.dist-info/licenses/LICENSE,sha256=p-v8m7Kmz4KKc7PcvsGiGEmCw9AiSXY4_ylOPy_u--Y,11343
161
- xai_review-0.10.0.dist-info/METADATA,sha256=eiLnNDKQiqcKlXpaAL2-rkF8mHENCWJtUAUliMzeVic,9618
162
- xai_review-0.10.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
163
- xai_review-0.10.0.dist-info/entry_points.txt,sha256=JyC5URanMi5io5P_PXQf7H_I1OGIpk5cZQhaPQ0g4Zs,53
164
- xai_review-0.10.0.dist-info/top_level.txt,sha256=sTsZbfzLoqvRZKdKa-BcxWvjlHdrpbeJ6DrGY0EuR0E,10
165
- xai_review-0.10.0.dist-info/RECORD,,
162
+ xai_review-0.12.0.dist-info/licenses/LICENSE,sha256=p-v8m7Kmz4KKc7PcvsGiGEmCw9AiSXY4_ylOPy_u--Y,11343
163
+ xai_review-0.12.0.dist-info/METADATA,sha256=LCwEqar1dH6shbzNbIh4hZkuLcz0pOrhWz27Rta769I,9618
164
+ xai_review-0.12.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
165
+ xai_review-0.12.0.dist-info/entry_points.txt,sha256=JyC5URanMi5io5P_PXQf7H_I1OGIpk5cZQhaPQ0g4Zs,53
166
+ xai_review-0.12.0.dist-info/top_level.txt,sha256=sTsZbfzLoqvRZKdKa-BcxWvjlHdrpbeJ6DrGY0EuR0E,10
167
+ xai_review-0.12.0.dist-info/RECORD,,