xai-review 0.26.0__tar.gz → 0.28.0__tar.gz

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.

Files changed (374) hide show
  1. {xai_review-0.26.0 → xai_review-0.28.0}/PKG-INFO +8 -5
  2. {xai_review-0.26.0 → xai_review-0.28.0}/README.md +7 -4
  3. xai_review-0.28.0/ai_review/cli/commands/run_inline_reply_review.py +7 -0
  4. xai_review-0.28.0/ai_review/cli/commands/run_summary_reply_review.py +7 -0
  5. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/cli/main.py +17 -0
  6. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/pr/client.py +45 -8
  7. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/pr/schema/comments.py +21 -2
  8. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/pr/schema/files.py +8 -3
  9. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/pr/schema/pull_request.py +1 -5
  10. xai_review-0.28.0/ai_review/clients/bitbucket/pr/schema/user.py +7 -0
  11. xai_review-0.28.0/ai_review/clients/bitbucket/tools.py +6 -0
  12. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/client.py +98 -13
  13. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/schema/comments.py +23 -1
  14. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/schema/files.py +2 -1
  15. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/schema/pull_request.py +1 -4
  16. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/schema/reviews.py +2 -1
  17. xai_review-0.28.0/ai_review/clients/github/pr/schema/user.py +6 -0
  18. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/types.py +11 -1
  19. xai_review-0.28.0/ai_review/clients/github/tools.py +6 -0
  20. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/mr/client.py +67 -7
  21. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/mr/schema/changes.py +1 -5
  22. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/mr/schema/discussions.py +19 -8
  23. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/mr/schema/notes.py +5 -1
  24. xai_review-0.28.0/ai_review/clients/gitlab/mr/schema/user.py +7 -0
  25. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/mr/types.py +16 -7
  26. xai_review-0.28.0/ai_review/clients/gitlab/tools.py +5 -0
  27. xai_review-0.28.0/ai_review/libs/config/prompt.py +155 -0
  28. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/review.py +2 -0
  29. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/vcs/base.py +2 -0
  30. xai_review-0.28.0/ai_review/libs/config/vcs/pagination.py +6 -0
  31. xai_review-0.28.0/ai_review/libs/http/paginate.py +43 -0
  32. xai_review-0.28.0/ai_review/libs/llm/output_json_parser.py +60 -0
  33. xai_review-0.28.0/ai_review/prompts/default_inline_reply.md +10 -0
  34. xai_review-0.28.0/ai_review/prompts/default_summary_reply.md +14 -0
  35. xai_review-0.28.0/ai_review/prompts/default_system_inline_reply.md +31 -0
  36. xai_review-0.28.0/ai_review/prompts/default_system_summary_reply.md +13 -0
  37. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/artifacts/schema.py +2 -2
  38. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/hook/constants.py +14 -0
  39. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/hook/service.py +95 -4
  40. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/hook/types.py +18 -2
  41. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/prompt/adapter.py +1 -1
  42. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/prompt/service.py +49 -3
  43. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/prompt/tools.py +21 -0
  44. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/prompt/types.py +23 -0
  45. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/review/gateway/comment.py +45 -6
  46. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/review/gateway/llm.py +2 -1
  47. xai_review-0.28.0/ai_review/services/review/gateway/types.py +50 -0
  48. xai_review-0.28.0/ai_review/services/review/internal/inline/service.py +40 -0
  49. xai_review-0.28.0/ai_review/services/review/internal/inline/types.py +8 -0
  50. xai_review-0.28.0/ai_review/services/review/internal/inline_reply/schema.py +23 -0
  51. xai_review-0.28.0/ai_review/services/review/internal/inline_reply/service.py +20 -0
  52. xai_review-0.28.0/ai_review/services/review/internal/inline_reply/types.py +8 -0
  53. {xai_review-0.26.0/ai_review/services/review → xai_review-0.28.0/ai_review/services/review/internal}/policy/service.py +2 -1
  54. xai_review-0.28.0/ai_review/services/review/internal/policy/types.py +15 -0
  55. {xai_review-0.26.0/ai_review/services/review → xai_review-0.28.0/ai_review/services/review/internal}/summary/service.py +2 -2
  56. {xai_review-0.26.0/ai_review/services/review → xai_review-0.28.0/ai_review/services/review/internal}/summary/types.py +1 -1
  57. xai_review-0.28.0/ai_review/services/review/internal/summary_reply/schema.py +8 -0
  58. xai_review-0.28.0/ai_review/services/review/internal/summary_reply/service.py +15 -0
  59. xai_review-0.28.0/ai_review/services/review/internal/summary_reply/types.py +8 -0
  60. xai_review-0.28.0/ai_review/services/review/runner/context.py +72 -0
  61. xai_review-0.28.0/ai_review/services/review/runner/inline.py +80 -0
  62. xai_review-0.28.0/ai_review/services/review/runner/inline_reply.py +80 -0
  63. xai_review-0.28.0/ai_review/services/review/runner/summary.py +71 -0
  64. xai_review-0.28.0/ai_review/services/review/runner/summary_reply.py +79 -0
  65. xai_review-0.28.0/ai_review/services/review/runner/types.py +6 -0
  66. xai_review-0.28.0/ai_review/services/review/service.py +127 -0
  67. xai_review-0.28.0/ai_review/services/vcs/bitbucket/adapter.py +24 -0
  68. xai_review-0.28.0/ai_review/services/vcs/bitbucket/client.py +250 -0
  69. xai_review-0.28.0/ai_review/services/vcs/github/adapter.py +35 -0
  70. xai_review-0.28.0/ai_review/services/vcs/github/client.py +232 -0
  71. xai_review-0.28.0/ai_review/services/vcs/gitlab/adapter.py +26 -0
  72. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/vcs/gitlab/client.py +91 -38
  73. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/vcs/types.py +34 -0
  74. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/clients/bitbucket.py +2 -2
  75. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/clients/github.py +35 -6
  76. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/clients/gitlab.py +42 -3
  77. xai_review-0.28.0/ai_review/tests/fixtures/libs/llm/output_json_parser.py +13 -0
  78. xai_review-0.28.0/ai_review/tests/fixtures/services/hook.py +8 -0
  79. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/services/llm.py +8 -5
  80. xai_review-0.28.0/ai_review/tests/fixtures/services/prompt.py +113 -0
  81. xai_review-0.28.0/ai_review/tests/fixtures/services/review/base.py +41 -0
  82. xai_review-0.28.0/ai_review/tests/fixtures/services/review/gateway/comment.py +98 -0
  83. xai_review-0.28.0/ai_review/tests/fixtures/services/review/gateway/llm.py +17 -0
  84. {xai_review-0.26.0/ai_review/tests/fixtures/services/review → xai_review-0.28.0/ai_review/tests/fixtures/services/review/internal}/inline.py +8 -6
  85. xai_review-0.28.0/ai_review/tests/fixtures/services/review/internal/inline_reply.py +25 -0
  86. xai_review-0.28.0/ai_review/tests/fixtures/services/review/internal/policy.py +28 -0
  87. xai_review-0.28.0/ai_review/tests/fixtures/services/review/internal/summary.py +21 -0
  88. xai_review-0.28.0/ai_review/tests/fixtures/services/review/internal/summary_reply.py +19 -0
  89. xai_review-0.28.0/ai_review/tests/fixtures/services/review/runner/context.py +50 -0
  90. xai_review-0.28.0/ai_review/tests/fixtures/services/review/runner/inline.py +50 -0
  91. xai_review-0.28.0/ai_review/tests/fixtures/services/review/runner/inline_reply.py +50 -0
  92. xai_review-0.28.0/ai_review/tests/fixtures/services/review/runner/summary.py +50 -0
  93. xai_review-0.28.0/ai_review/tests/fixtures/services/review/runner/summary_reply.py +50 -0
  94. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/services/vcs.py +23 -0
  95. xai_review-0.28.0/ai_review/tests/suites/cli/test_main.py +54 -0
  96. xai_review-0.28.0/ai_review/tests/suites/clients/bitbucket/test_client.py +14 -0
  97. xai_review-0.28.0/ai_review/tests/suites/clients/bitbucket/test_tools.py +31 -0
  98. xai_review-0.28.0/ai_review/tests/suites/clients/github/test_tools.py +31 -0
  99. xai_review-0.28.0/ai_review/tests/suites/clients/gitlab/test_tools.py +26 -0
  100. xai_review-0.28.0/ai_review/tests/suites/libs/config/test_prompt.py +137 -0
  101. xai_review-0.28.0/ai_review/tests/suites/libs/http/test_paginate.py +95 -0
  102. xai_review-0.28.0/ai_review/tests/suites/libs/llm/test_output_json_parser.py +155 -0
  103. xai_review-0.28.0/ai_review/tests/suites/services/hook/test_service.py +177 -0
  104. xai_review-0.28.0/ai_review/tests/suites/services/llm/__init__.py +0 -0
  105. xai_review-0.28.0/ai_review/tests/suites/services/llm/claude/__init__.py +0 -0
  106. xai_review-0.28.0/ai_review/tests/suites/services/llm/gemini/__init__.py +0 -0
  107. xai_review-0.28.0/ai_review/tests/suites/services/llm/ollama/__init__.py +0 -0
  108. xai_review-0.28.0/ai_review/tests/suites/services/llm/openai/__init__.py +0 -0
  109. xai_review-0.28.0/ai_review/tests/suites/services/prompt/__init__.py +0 -0
  110. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/prompt/test_adapter.py +3 -3
  111. xai_review-0.28.0/ai_review/tests/suites/services/prompt/test_service.py +215 -0
  112. xai_review-0.28.0/ai_review/tests/suites/services/prompt/test_tools.py +157 -0
  113. xai_review-0.28.0/ai_review/tests/suites/services/review/__init__.py +0 -0
  114. xai_review-0.28.0/ai_review/tests/suites/services/review/gateway/__init__.py +0 -0
  115. xai_review-0.28.0/ai_review/tests/suites/services/review/gateway/test_comment.py +253 -0
  116. xai_review-0.28.0/ai_review/tests/suites/services/review/gateway/test_llm.py +82 -0
  117. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/__init__.py +0 -0
  118. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/inline/__init__.py +0 -0
  119. {xai_review-0.26.0/ai_review/tests/suites/services/review → xai_review-0.28.0/ai_review/tests/suites/services/review/internal}/inline/test_schema.py +1 -1
  120. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/inline/test_service.py +81 -0
  121. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/inline_reply/__init__.py +0 -0
  122. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/inline_reply/test_schema.py +57 -0
  123. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/inline_reply/test_service.py +72 -0
  124. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/policy/__init__.py +0 -0
  125. {xai_review-0.26.0/ai_review/tests/suites/services/review → xai_review-0.28.0/ai_review/tests/suites/services/review/internal}/policy/test_service.py +1 -1
  126. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/summary/__init__.py +0 -0
  127. {xai_review-0.26.0/ai_review/tests/suites/services/review → xai_review-0.28.0/ai_review/tests/suites/services/review/internal}/summary/test_schema.py +1 -1
  128. {xai_review-0.26.0/ai_review/tests/suites/services/review → xai_review-0.28.0/ai_review/tests/suites/services/review/internal}/summary/test_service.py +2 -2
  129. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/summary_reply/__init__.py +0 -0
  130. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/summary_reply/test_schema.py +19 -0
  131. xai_review-0.28.0/ai_review/tests/suites/services/review/internal/summary_reply/test_service.py +21 -0
  132. xai_review-0.28.0/ai_review/tests/suites/services/review/runner/__init__.py +0 -0
  133. xai_review-0.28.0/ai_review/tests/suites/services/review/runner/test_context.py +89 -0
  134. xai_review-0.28.0/ai_review/tests/suites/services/review/runner/test_inline.py +100 -0
  135. xai_review-0.28.0/ai_review/tests/suites/services/review/runner/test_inline_reply.py +109 -0
  136. xai_review-0.28.0/ai_review/tests/suites/services/review/runner/test_summary.py +87 -0
  137. xai_review-0.28.0/ai_review/tests/suites/services/review/runner/test_summary_reply.py +97 -0
  138. xai_review-0.28.0/ai_review/tests/suites/services/review/test_service.py +93 -0
  139. xai_review-0.28.0/ai_review/tests/suites/services/vcs/__init__.py +0 -0
  140. xai_review-0.28.0/ai_review/tests/suites/services/vcs/bitbucket/__init__.py +0 -0
  141. xai_review-0.28.0/ai_review/tests/suites/services/vcs/bitbucket/test_adapter.py +109 -0
  142. xai_review-0.26.0/ai_review/tests/suites/services/vcs/bitbucket/test_service.py → xai_review-0.28.0/ai_review/tests/suites/services/vcs/bitbucket/test_client.py +88 -1
  143. xai_review-0.28.0/ai_review/tests/suites/services/vcs/github/__init__.py +0 -0
  144. xai_review-0.28.0/ai_review/tests/suites/services/vcs/github/test_adapter.py +162 -0
  145. xai_review-0.26.0/ai_review/tests/suites/services/vcs/github/test_service.py → xai_review-0.28.0/ai_review/tests/suites/services/vcs/github/test_client.py +102 -2
  146. xai_review-0.28.0/ai_review/tests/suites/services/vcs/gitlab/__init__.py +0 -0
  147. xai_review-0.28.0/ai_review/tests/suites/services/vcs/gitlab/test_adapter.py +105 -0
  148. xai_review-0.26.0/ai_review/tests/suites/services/vcs/gitlab/test_service.py → xai_review-0.28.0/ai_review/tests/suites/services/vcs/gitlab/test_client.py +99 -1
  149. {xai_review-0.26.0 → xai_review-0.28.0}/pyproject.toml +1 -1
  150. {xai_review-0.26.0 → xai_review-0.28.0}/xai_review.egg-info/PKG-INFO +8 -5
  151. {xai_review-0.26.0 → xai_review-0.28.0}/xai_review.egg-info/SOURCES.txt +108 -23
  152. xai_review-0.26.0/ai_review/libs/config/prompt.py +0 -123
  153. xai_review-0.26.0/ai_review/services/review/inline/service.py +0 -54
  154. xai_review-0.26.0/ai_review/services/review/inline/types.py +0 -11
  155. xai_review-0.26.0/ai_review/services/review/service.py +0 -159
  156. xai_review-0.26.0/ai_review/services/vcs/bitbucket/client.py +0 -185
  157. xai_review-0.26.0/ai_review/services/vcs/github/client.py +0 -171
  158. xai_review-0.26.0/ai_review/tests/fixtures/services/prompt.py +0 -43
  159. xai_review-0.26.0/ai_review/tests/fixtures/services/review/summary.py +0 -19
  160. xai_review-0.26.0/ai_review/tests/suites/libs/config/test_prompt.py +0 -57
  161. xai_review-0.26.0/ai_review/tests/suites/services/hook/test_service.py +0 -93
  162. xai_review-0.26.0/ai_review/tests/suites/services/prompt/test_service.py +0 -171
  163. xai_review-0.26.0/ai_review/tests/suites/services/prompt/test_tools.py +0 -72
  164. xai_review-0.26.0/ai_review/tests/suites/services/review/inline/test_service.py +0 -107
  165. xai_review-0.26.0/ai_review/tests/suites/services/review/test_service.py +0 -126
  166. {xai_review-0.26.0 → xai_review-0.28.0}/LICENSE +0 -0
  167. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/__init__.py +0 -0
  168. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/cli/__init__.py +0 -0
  169. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/cli/commands/__init__.py +0 -0
  170. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/cli/commands/run_context_review.py +0 -0
  171. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/cli/commands/run_inline_review.py +0 -0
  172. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/cli/commands/run_review.py +0 -0
  173. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/cli/commands/run_summary_review.py +0 -0
  174. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/__init__.py +0 -0
  175. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/__init__.py +0 -0
  176. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/client.py +0 -0
  177. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/pr/__init__.py +0 -0
  178. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/pr/schema/__init__.py +0 -0
  179. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/bitbucket/pr/types.py +0 -0
  180. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/claude/__init__.py +0 -0
  181. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/claude/client.py +0 -0
  182. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/claude/schema.py +0 -0
  183. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/claude/types.py +0 -0
  184. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gemini/__init__.py +0 -0
  185. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gemini/client.py +0 -0
  186. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gemini/schema.py +0 -0
  187. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gemini/types.py +0 -0
  188. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/__init__.py +0 -0
  189. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/client.py +0 -0
  190. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/__init__.py +0 -0
  191. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/github/pr/schema/__init__.py +0 -0
  192. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/__init__.py +0 -0
  193. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/client.py +0 -0
  194. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/mr/__init__.py +0 -0
  195. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/gitlab/mr/schema/__init__.py +0 -0
  196. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/ollama/__init__.py +0 -0
  197. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/ollama/client.py +0 -0
  198. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/ollama/schema.py +0 -0
  199. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/ollama/types.py +0 -0
  200. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/openai/__init__.py +0 -0
  201. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/openai/client.py +0 -0
  202. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/openai/schema.py +0 -0
  203. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/clients/openai/types.py +0 -0
  204. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/config.py +0 -0
  205. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/__init__.py +0 -0
  206. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/asynchronous/__init__.py +0 -0
  207. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/asynchronous/gather.py +0 -0
  208. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/__init__.py +0 -0
  209. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/artifacts.py +0 -0
  210. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/base.py +0 -0
  211. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/core.py +0 -0
  212. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/http.py +0 -0
  213. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/llm/__init__.py +0 -0
  214. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/llm/base.py +0 -0
  215. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/llm/claude.py +0 -0
  216. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/llm/gemini.py +0 -0
  217. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/llm/meta.py +0 -0
  218. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/llm/ollama.py +0 -0
  219. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/llm/openai.py +0 -0
  220. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/logger.py +0 -0
  221. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/vcs/__init__.py +0 -0
  222. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/vcs/bitbucket.py +0 -0
  223. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/vcs/github.py +0 -0
  224. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/config/vcs/gitlab.py +0 -0
  225. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/constants/__init__.py +0 -0
  226. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/constants/llm_provider.py +0 -0
  227. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/constants/vcs_provider.py +0 -0
  228. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/diff/__init__.py +0 -0
  229. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/diff/models.py +0 -0
  230. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/diff/parser.py +0 -0
  231. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/diff/tools.py +0 -0
  232. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/__init__.py +0 -0
  233. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/client.py +0 -0
  234. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/event_hooks/__init__.py +0 -0
  235. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/event_hooks/base.py +0 -0
  236. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/event_hooks/logger.py +0 -0
  237. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/handlers.py +0 -0
  238. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/transports/__init__.py +0 -0
  239. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/http/transports/retry.py +0 -0
  240. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/json.py +0 -0
  241. {xai_review-0.26.0/ai_review/libs/template → xai_review-0.28.0/ai_review/libs/llm}/__init__.py +0 -0
  242. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/logger.py +0 -0
  243. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/resources.py +0 -0
  244. {xai_review-0.26.0/ai_review/prompts → xai_review-0.28.0/ai_review/libs/template}/__init__.py +0 -0
  245. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/libs/template/render.py +0 -0
  246. {xai_review-0.26.0/ai_review/resources → xai_review-0.28.0/ai_review/prompts}/__init__.py +0 -0
  247. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/prompts/default_context.md +0 -0
  248. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/prompts/default_inline.md +0 -0
  249. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/prompts/default_summary.md +0 -0
  250. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/prompts/default_system_context.md +0 -0
  251. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/prompts/default_system_inline.md +0 -0
  252. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/prompts/default_system_summary.md +0 -0
  253. {xai_review-0.26.0/ai_review/services → xai_review-0.28.0/ai_review/resources}/__init__.py +0 -0
  254. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/resources/pricing.yaml +0 -0
  255. {xai_review-0.26.0/ai_review/services/artifacts → xai_review-0.28.0/ai_review/services}/__init__.py +0 -0
  256. {xai_review-0.26.0/ai_review/services/cost → xai_review-0.28.0/ai_review/services/artifacts}/__init__.py +0 -0
  257. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/artifacts/service.py +0 -0
  258. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/artifacts/tools.py +0 -0
  259. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/artifacts/types.py +0 -0
  260. {xai_review-0.26.0/ai_review/services/diff → xai_review-0.28.0/ai_review/services/cost}/__init__.py +0 -0
  261. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/cost/schema.py +0 -0
  262. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/cost/service.py +0 -0
  263. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/cost/types.py +0 -0
  264. {xai_review-0.26.0/ai_review/services/git → xai_review-0.28.0/ai_review/services/diff}/__init__.py +0 -0
  265. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/diff/renderers.py +0 -0
  266. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/diff/schema.py +0 -0
  267. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/diff/service.py +0 -0
  268. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/diff/tools.py +0 -0
  269. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/diff/types.py +0 -0
  270. {xai_review-0.26.0/ai_review/services/llm → xai_review-0.28.0/ai_review/services/git}/__init__.py +0 -0
  271. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/git/service.py +0 -0
  272. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/git/types.py +0 -0
  273. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/hook/__init__.py +0 -0
  274. {xai_review-0.26.0/ai_review/services/llm/claude → xai_review-0.28.0/ai_review/services/llm}/__init__.py +0 -0
  275. {xai_review-0.26.0/ai_review/services/llm/gemini → xai_review-0.28.0/ai_review/services/llm/claude}/__init__.py +0 -0
  276. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/llm/claude/client.py +0 -0
  277. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/llm/factory.py +0 -0
  278. {xai_review-0.26.0/ai_review/services/llm/ollama → xai_review-0.28.0/ai_review/services/llm/gemini}/__init__.py +0 -0
  279. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/llm/gemini/client.py +0 -0
  280. {xai_review-0.26.0/ai_review/services/llm/openai → xai_review-0.28.0/ai_review/services/llm/ollama}/__init__.py +0 -0
  281. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/llm/ollama/client.py +0 -0
  282. {xai_review-0.26.0/ai_review/services/prompt → xai_review-0.28.0/ai_review/services/llm/openai}/__init__.py +0 -0
  283. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/llm/openai/client.py +0 -0
  284. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/llm/types.py +0 -0
  285. {xai_review-0.26.0/ai_review/services/review → xai_review-0.28.0/ai_review/services/prompt}/__init__.py +0 -0
  286. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/prompt/schema.py +0 -0
  287. {xai_review-0.26.0/ai_review/services/review/gateway → xai_review-0.28.0/ai_review/services/review}/__init__.py +0 -0
  288. {xai_review-0.26.0/ai_review/services/review/inline → xai_review-0.28.0/ai_review/services/review/gateway}/__init__.py +0 -0
  289. {xai_review-0.26.0/ai_review/services/review/policy → xai_review-0.28.0/ai_review/services/review/internal}/__init__.py +0 -0
  290. {xai_review-0.26.0/ai_review/services/review/summary → xai_review-0.28.0/ai_review/services/review/internal/inline}/__init__.py +0 -0
  291. {xai_review-0.26.0/ai_review/services/review → xai_review-0.28.0/ai_review/services/review/internal}/inline/schema.py +0 -0
  292. {xai_review-0.26.0/ai_review/services/vcs → xai_review-0.28.0/ai_review/services/review/internal/inline_reply}/__init__.py +0 -0
  293. {xai_review-0.26.0/ai_review/services/vcs/bitbucket → xai_review-0.28.0/ai_review/services/review/internal/policy}/__init__.py +0 -0
  294. {xai_review-0.26.0/ai_review/services/vcs/github → xai_review-0.28.0/ai_review/services/review/internal/summary}/__init__.py +0 -0
  295. {xai_review-0.26.0/ai_review/services/review → xai_review-0.28.0/ai_review/services/review/internal}/summary/schema.py +0 -0
  296. {xai_review-0.26.0/ai_review/services/vcs/gitlab → xai_review-0.28.0/ai_review/services/review/internal/summary_reply}/__init__.py +0 -0
  297. {xai_review-0.26.0/ai_review/tests → xai_review-0.28.0/ai_review/services/review/runner}/__init__.py +0 -0
  298. {xai_review-0.26.0/ai_review/tests/fixtures → xai_review-0.28.0/ai_review/services/vcs}/__init__.py +0 -0
  299. {xai_review-0.26.0/ai_review/tests/fixtures/clients → xai_review-0.28.0/ai_review/services/vcs/bitbucket}/__init__.py +0 -0
  300. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/services/vcs/factory.py +0 -0
  301. {xai_review-0.26.0/ai_review/tests/fixtures/services → xai_review-0.28.0/ai_review/services/vcs/github}/__init__.py +0 -0
  302. {xai_review-0.26.0/ai_review/tests/fixtures/services/review → xai_review-0.28.0/ai_review/services/vcs/gitlab}/__init__.py +0 -0
  303. {xai_review-0.26.0/ai_review/tests/suites → xai_review-0.28.0/ai_review/tests}/__init__.py +0 -0
  304. {xai_review-0.26.0/ai_review/tests/suites/clients → xai_review-0.28.0/ai_review/tests/fixtures}/__init__.py +0 -0
  305. {xai_review-0.26.0/ai_review/tests/suites/clients/claude → xai_review-0.28.0/ai_review/tests/fixtures/clients}/__init__.py +0 -0
  306. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/clients/claude.py +0 -0
  307. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/clients/gemini.py +0 -0
  308. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/clients/ollama.py +0 -0
  309. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/clients/openai.py +0 -0
  310. {xai_review-0.26.0/ai_review/tests/suites/clients/gemini → xai_review-0.28.0/ai_review/tests/fixtures/libs}/__init__.py +0 -0
  311. {xai_review-0.26.0/ai_review/tests/suites/clients/github → xai_review-0.28.0/ai_review/tests/fixtures/libs/llm}/__init__.py +0 -0
  312. {xai_review-0.26.0/ai_review/tests/suites/clients/gitlab → xai_review-0.28.0/ai_review/tests/fixtures/services}/__init__.py +0 -0
  313. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/services/artifacts.py +0 -0
  314. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/services/cost.py +0 -0
  315. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/services/diff.py +0 -0
  316. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/fixtures/services/git.py +0 -0
  317. {xai_review-0.26.0/ai_review/tests/suites/clients/ollama → xai_review-0.28.0/ai_review/tests/fixtures/services/review}/__init__.py +0 -0
  318. {xai_review-0.26.0/ai_review/tests/suites/clients/openai → xai_review-0.28.0/ai_review/tests/fixtures/services/review/gateway}/__init__.py +0 -0
  319. {xai_review-0.26.0/ai_review/tests/suites/libs → xai_review-0.28.0/ai_review/tests/fixtures/services/review/internal}/__init__.py +0 -0
  320. {xai_review-0.26.0/ai_review/tests/suites/libs/asynchronous → xai_review-0.28.0/ai_review/tests/fixtures/services/review/runner}/__init__.py +0 -0
  321. {xai_review-0.26.0/ai_review/tests/suites/libs/config → xai_review-0.28.0/ai_review/tests/suites}/__init__.py +0 -0
  322. {xai_review-0.26.0/ai_review/tests/suites/libs/diff → xai_review-0.28.0/ai_review/tests/suites/cli}/__init__.py +0 -0
  323. {xai_review-0.26.0/ai_review/tests/suites/libs/template → xai_review-0.28.0/ai_review/tests/suites/clients}/__init__.py +0 -0
  324. {xai_review-0.26.0/ai_review/tests/suites/services → xai_review-0.28.0/ai_review/tests/suites/clients/bitbucket}/__init__.py +0 -0
  325. {xai_review-0.26.0/ai_review/tests/suites/services/cost → xai_review-0.28.0/ai_review/tests/suites/clients/claude}/__init__.py +0 -0
  326. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/claude/test_client.py +0 -0
  327. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/claude/test_schema.py +0 -0
  328. {xai_review-0.26.0/ai_review/tests/suites/services/diff → xai_review-0.28.0/ai_review/tests/suites/clients/gemini}/__init__.py +0 -0
  329. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/gemini/test_client.py +0 -0
  330. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/gemini/test_schema.py +0 -0
  331. {xai_review-0.26.0/ai_review/tests/suites/services/hook → xai_review-0.28.0/ai_review/tests/suites/clients/github}/__init__.py +0 -0
  332. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/github/test_client.py +0 -0
  333. {xai_review-0.26.0/ai_review/tests/suites/services/llm → xai_review-0.28.0/ai_review/tests/suites/clients/gitlab}/__init__.py +0 -0
  334. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/gitlab/test_client.py +0 -0
  335. {xai_review-0.26.0/ai_review/tests/suites/services/llm/claude → xai_review-0.28.0/ai_review/tests/suites/clients/ollama}/__init__.py +0 -0
  336. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/ollama/test_client.py +0 -0
  337. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/ollama/test_schema.py +0 -0
  338. {xai_review-0.26.0/ai_review/tests/suites/services/llm/gemini → xai_review-0.28.0/ai_review/tests/suites/clients/openai}/__init__.py +0 -0
  339. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/openai/test_client.py +0 -0
  340. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/clients/openai/test_schema.py +0 -0
  341. {xai_review-0.26.0/ai_review/tests/suites/services/llm/ollama → xai_review-0.28.0/ai_review/tests/suites/libs}/__init__.py +0 -0
  342. {xai_review-0.26.0/ai_review/tests/suites/services/llm/openai → xai_review-0.28.0/ai_review/tests/suites/libs/asynchronous}/__init__.py +0 -0
  343. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/libs/asynchronous/test_gather.py +0 -0
  344. {xai_review-0.26.0/ai_review/tests/suites/services/prompt → xai_review-0.28.0/ai_review/tests/suites/libs/config}/__init__.py +0 -0
  345. {xai_review-0.26.0/ai_review/tests/suites/services/review → xai_review-0.28.0/ai_review/tests/suites/libs/diff}/__init__.py +0 -0
  346. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/libs/diff/test_models.py +0 -0
  347. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/libs/diff/test_parser.py +0 -0
  348. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/libs/diff/test_tools.py +0 -0
  349. {xai_review-0.26.0/ai_review/tests/suites/services/review/inline → xai_review-0.28.0/ai_review/tests/suites/libs/http}/__init__.py +0 -0
  350. {xai_review-0.26.0/ai_review/tests/suites/services/review/policy → xai_review-0.28.0/ai_review/tests/suites/libs/llm}/__init__.py +0 -0
  351. {xai_review-0.26.0/ai_review/tests/suites/services/review/summary → xai_review-0.28.0/ai_review/tests/suites/libs/template}/__init__.py +0 -0
  352. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/libs/template/test_render.py +0 -0
  353. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/libs/test_json.py +0 -0
  354. {xai_review-0.26.0/ai_review/tests/suites/services/vcs → xai_review-0.28.0/ai_review/tests/suites/services}/__init__.py +0 -0
  355. {xai_review-0.26.0/ai_review/tests/suites/services/vcs/bitbucket → xai_review-0.28.0/ai_review/tests/suites/services/cost}/__init__.py +0 -0
  356. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/cost/test_schema.py +0 -0
  357. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/cost/test_service.py +0 -0
  358. {xai_review-0.26.0/ai_review/tests/suites/services/vcs/github → xai_review-0.28.0/ai_review/tests/suites/services/diff}/__init__.py +0 -0
  359. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/diff/test_renderers.py +0 -0
  360. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/diff/test_service.py +0 -0
  361. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/diff/test_tools.py +0 -0
  362. {xai_review-0.26.0/ai_review/tests/suites/services/vcs/gitlab → xai_review-0.28.0/ai_review/tests/suites/services/hook}/__init__.py +0 -0
  363. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/llm/claude/test_client.py +0 -0
  364. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/llm/gemini/test_client.py +0 -0
  365. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/llm/ollama/test_client.py +0 -0
  366. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/llm/openai/test_client.py +0 -0
  367. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/llm/test_factory.py +0 -0
  368. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/prompt/test_schema.py +0 -0
  369. {xai_review-0.26.0 → xai_review-0.28.0}/ai_review/tests/suites/services/vcs/test_factory.py +0 -0
  370. {xai_review-0.26.0 → xai_review-0.28.0}/setup.cfg +0 -0
  371. {xai_review-0.26.0 → xai_review-0.28.0}/xai_review.egg-info/dependency_links.txt +0 -0
  372. {xai_review-0.26.0 → xai_review-0.28.0}/xai_review.egg-info/entry_points.txt +0 -0
  373. {xai_review-0.26.0 → xai_review-0.28.0}/xai_review.egg-info/requires.txt +0 -0
  374. {xai_review-0.26.0 → xai_review-0.28.0}/xai_review.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xai-review
3
- Version: 0.26.0
3
+ Version: 0.28.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>
@@ -69,12 +69,14 @@ improve code quality, enforce consistency, and speed up the review process.
69
69
  - **Multiple LLM providers** — choose between **OpenAI**, **Claude**, **Gemini**, or **Ollama**, and switch anytime.
70
70
  - **VCS integration** — works out of the box with **GitLab**, **GitHub**, and **Bitbucket**.
71
71
  - **Customizable prompts** — adapt inline, context, and summary reviews to match your team’s coding guidelines.
72
+ - **Reply modes** — AI can now **participate in existing review threads**, adding follow-up replies in both inline and
73
+ summary discussions.
72
74
  - **Flexible configuration** — supports `YAML`, `JSON`, and `ENV`, with seamless overrides in CI/CD pipelines.
73
75
  - **AI Review runs fully client-side** — it never proxies or inspects your requests.
74
76
 
75
- AI Review runs automatically in your CI/CD pipeline and posts both **inline comments** and **summary reviews** right
76
- inside your merge requests. This makes reviews faster, more consistent, and less error-prone — while still leaving the
77
- final decision to human reviewers.
77
+ AI Review runs automatically in your CI/CD pipeline and posts both **inline comments**, **summary reviews**, and now *
78
+ *AI-generated replies** directly inside your merge requests. This makes reviews faster, more conversational, and still
79
+ fully under human control.
78
80
 
79
81
  ---
80
82
 
@@ -209,7 +211,7 @@ jobs:
209
211
  runs-on: ubuntu-latest
210
212
  steps:
211
213
  - uses: actions/checkout@v4
212
- - uses: Nikita-Filonov/ai-review@v0.26.0
214
+ - uses: Nikita-Filonov/ai-review@v0.28.0
213
215
  with:
214
216
  review-command: ${{ inputs.review-command }}
215
217
  env:
@@ -274,6 +276,7 @@ ai-review:
274
276
  See these folders for reference templates and full configuration options:
275
277
 
276
278
  - [./docs/ci](./docs/ci) — CI/CD integration templates (GitHub Actions, GitLab CI)
279
+ - [./docs/cli](./docs/cli) — CLI command reference and usage examples
277
280
  - [./docs/hooks](./docs/hooks) — hook reference and lifecycle events
278
281
  - [./docs/configs](./docs/configs) — full configuration examples (`.yaml`, `.json`, `.env`)
279
282
  - [./docs/prompts](./docs/prompts) — prompt templates for Python/Go (light & strict modes)
@@ -35,12 +35,14 @@ improve code quality, enforce consistency, and speed up the review process.
35
35
  - **Multiple LLM providers** — choose between **OpenAI**, **Claude**, **Gemini**, or **Ollama**, and switch anytime.
36
36
  - **VCS integration** — works out of the box with **GitLab**, **GitHub**, and **Bitbucket**.
37
37
  - **Customizable prompts** — adapt inline, context, and summary reviews to match your team’s coding guidelines.
38
+ - **Reply modes** — AI can now **participate in existing review threads**, adding follow-up replies in both inline and
39
+ summary discussions.
38
40
  - **Flexible configuration** — supports `YAML`, `JSON`, and `ENV`, with seamless overrides in CI/CD pipelines.
39
41
  - **AI Review runs fully client-side** — it never proxies or inspects your requests.
40
42
 
41
- AI Review runs automatically in your CI/CD pipeline and posts both **inline comments** and **summary reviews** right
42
- inside your merge requests. This makes reviews faster, more consistent, and less error-prone — while still leaving the
43
- final decision to human reviewers.
43
+ AI Review runs automatically in your CI/CD pipeline and posts both **inline comments**, **summary reviews**, and now *
44
+ *AI-generated replies** directly inside your merge requests. This makes reviews faster, more conversational, and still
45
+ fully under human control.
44
46
 
45
47
  ---
46
48
 
@@ -175,7 +177,7 @@ jobs:
175
177
  runs-on: ubuntu-latest
176
178
  steps:
177
179
  - uses: actions/checkout@v4
178
- - uses: Nikita-Filonov/ai-review@v0.26.0
180
+ - uses: Nikita-Filonov/ai-review@v0.28.0
179
181
  with:
180
182
  review-command: ${{ inputs.review-command }}
181
183
  env:
@@ -240,6 +242,7 @@ ai-review:
240
242
  See these folders for reference templates and full configuration options:
241
243
 
242
244
  - [./docs/ci](./docs/ci) — CI/CD integration templates (GitHub Actions, GitLab CI)
245
+ - [./docs/cli](./docs/cli) — CLI command reference and usage examples
243
246
  - [./docs/hooks](./docs/hooks) — hook reference and lifecycle events
244
247
  - [./docs/configs](./docs/configs) — full configuration examples (`.yaml`, `.json`, `.env`)
245
248
  - [./docs/prompts](./docs/prompts) — prompt templates for Python/Go (light & strict modes)
@@ -0,0 +1,7 @@
1
+ from ai_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_inline_reply_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_inline_reply_review()
7
+ review_service.report_total_cost()
@@ -0,0 +1,7 @@
1
+ from ai_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_summary_reply_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_summary_reply_review()
7
+ review_service.report_total_cost()
@@ -3,8 +3,10 @@ import asyncio
3
3
  import typer
4
4
 
5
5
  from ai_review.cli.commands.run_context_review import run_context_review_command
6
+ from ai_review.cli.commands.run_inline_reply_review import run_inline_reply_review_command
6
7
  from ai_review.cli.commands.run_inline_review import run_inline_review_command
7
8
  from ai_review.cli.commands.run_review import run_review_command
9
+ from ai_review.cli.commands.run_summary_reply_review import run_summary_reply_review_command
8
10
  from ai_review.cli.commands.run_summary_review import run_summary_review_command
9
11
  from ai_review.config import settings
10
12
 
@@ -43,6 +45,21 @@ def run_summary():
43
45
  typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
44
46
 
45
47
 
48
+ @app.command("run-inline-reply")
49
+ def run_inline_reply():
50
+ """Run only the inline reply review"""
51
+ typer.secho("Starting inline reply AI review...", fg=typer.colors.CYAN)
52
+ asyncio.run(run_inline_reply_review_command())
53
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
54
+
55
+
56
+ @app.command("run-summary-reply")
57
+ def run_summary_reply():
58
+ typer.secho("Starting summary reply AI review...", fg=typer.colors.CYAN)
59
+ asyncio.run(run_summary_reply_review_command())
60
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
61
+
62
+
46
63
  @app.command("show-config")
47
64
  def show_config():
48
65
  """Show the current resolved configuration"""
@@ -1,19 +1,24 @@
1
1
  from httpx import Response, QueryParams
2
2
 
3
3
  from ai_review.clients.bitbucket.pr.schema.comments import (
4
+ BitbucketPRCommentSchema,
4
5
  BitbucketGetPRCommentsQuerySchema,
5
6
  BitbucketGetPRCommentsResponseSchema,
6
7
  BitbucketCreatePRCommentRequestSchema,
7
8
  BitbucketCreatePRCommentResponseSchema,
8
9
  )
9
10
  from ai_review.clients.bitbucket.pr.schema.files import (
11
+ BitbucketPRFileSchema,
10
12
  BitbucketGetPRFilesQuerySchema,
11
13
  BitbucketGetPRFilesResponseSchema,
12
14
  )
13
15
  from ai_review.clients.bitbucket.pr.schema.pull_request import BitbucketGetPRResponseSchema
14
16
  from ai_review.clients.bitbucket.pr.types import BitbucketPullRequestsHTTPClientProtocol
17
+ from ai_review.clients.bitbucket.tools import bitbucket_has_next_page
18
+ from ai_review.config import settings
15
19
  from ai_review.libs.http.client import HTTPClient
16
20
  from ai_review.libs.http.handlers import handle_http_error, HTTPClientError
21
+ from ai_review.libs.http.paginate import paginate
17
22
 
18
23
 
19
24
  class BitbucketPullRequestsHTTPClientError(HTTPClientError):
@@ -35,7 +40,7 @@ class BitbucketPullRequestsHTTPClient(HTTPClient, BitbucketPullRequestsHTTPClien
35
40
  ) -> Response:
36
41
  return await self.get(
37
42
  f"/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/diffstat",
38
- query=QueryParams(**query.model_dump()),
43
+ query=QueryParams(**query.model_dump(by_alias=True)),
39
44
  )
40
45
 
41
46
  @handle_http_error(client="BitbucketPullRequestsHTTPClient", exception=BitbucketPullRequestsHTTPClientError)
@@ -48,7 +53,7 @@ class BitbucketPullRequestsHTTPClient(HTTPClient, BitbucketPullRequestsHTTPClien
48
53
  ) -> Response:
49
54
  return await self.get(
50
55
  f"/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/comments",
51
- query=QueryParams(**query.model_dump()),
56
+ query=QueryParams(**query.model_dump(by_alias=True)),
52
57
  )
53
58
 
54
59
  @handle_http_error(client="BitbucketPullRequestsHTTPClient", exception=BitbucketPullRequestsHTTPClientError)
@@ -79,9 +84,25 @@ class BitbucketPullRequestsHTTPClient(HTTPClient, BitbucketPullRequestsHTTPClien
79
84
  repo_slug: str,
80
85
  pull_request_id: str
81
86
  ) -> BitbucketGetPRFilesResponseSchema:
82
- query = BitbucketGetPRFilesQuerySchema(pagelen=100)
83
- resp = await self.get_diffstat_api(workspace, repo_slug, pull_request_id, query)
84
- return BitbucketGetPRFilesResponseSchema.model_validate_json(resp.text)
87
+ async def fetch_page(page: int) -> Response:
88
+ query = BitbucketGetPRFilesQuerySchema(page=page, page_len=settings.vcs.pagination.per_page)
89
+ return await self.get_diffstat_api(workspace, repo_slug, pull_request_id, query)
90
+
91
+ def extract_items(response: Response) -> list[BitbucketPRFileSchema]:
92
+ result = BitbucketGetPRFilesResponseSchema.model_validate_json(response.text)
93
+ return result.values
94
+
95
+ items = await paginate(
96
+ max_pages=settings.vcs.pagination.max_pages,
97
+ fetch_page=fetch_page,
98
+ extract_items=extract_items,
99
+ has_next_page=bitbucket_has_next_page
100
+ )
101
+ return BitbucketGetPRFilesResponseSchema(
102
+ size=len(items),
103
+ values=items,
104
+ page_len=settings.vcs.pagination.per_page
105
+ )
85
106
 
86
107
  async def get_comments(
87
108
  self,
@@ -89,9 +110,25 @@ class BitbucketPullRequestsHTTPClient(HTTPClient, BitbucketPullRequestsHTTPClien
89
110
  repo_slug: str,
90
111
  pull_request_id: str
91
112
  ) -> BitbucketGetPRCommentsResponseSchema:
92
- query = BitbucketGetPRCommentsQuerySchema(pagelen=100)
93
- response = await self.get_comments_api(workspace, repo_slug, pull_request_id, query)
94
- return BitbucketGetPRCommentsResponseSchema.model_validate_json(response.text)
113
+ async def fetch_page(page: int) -> Response:
114
+ query = BitbucketGetPRCommentsQuerySchema(page=page, page_len=settings.vcs.pagination.per_page)
115
+ return await self.get_comments_api(workspace, repo_slug, pull_request_id, query)
116
+
117
+ def extract_items(response: Response) -> list[BitbucketPRCommentSchema]:
118
+ result = BitbucketGetPRCommentsResponseSchema.model_validate_json(response.text)
119
+ return result.values
120
+
121
+ items = await paginate(
122
+ max_pages=settings.vcs.pagination.max_pages,
123
+ fetch_page=fetch_page,
124
+ extract_items=extract_items,
125
+ has_next_page=bitbucket_has_next_page
126
+ )
127
+ return BitbucketGetPRCommentsResponseSchema(
128
+ size=len(items),
129
+ values=items,
130
+ page_len=settings.vcs.pagination.per_page
131
+ )
95
132
 
96
133
  async def create_comment(
97
134
  self,
@@ -1,5 +1,7 @@
1
1
  from pydantic import BaseModel, Field, ConfigDict
2
2
 
3
+ from ai_review.clients.bitbucket.pr.schema.user import BitbucketUserSchema
4
+
3
5
 
4
6
  class BitbucketCommentContentSchema(BaseModel):
5
7
  raw: str
@@ -15,30 +17,47 @@ class BitbucketCommentInlineSchema(BaseModel):
15
17
  from_line: int | None = Field(alias="from", default=None)
16
18
 
17
19
 
20
+ class BitbucketCommentParentSchema(BaseModel):
21
+ id: int
22
+
23
+
18
24
  class BitbucketPRCommentSchema(BaseModel):
19
25
  id: int
26
+ user: BitbucketUserSchema | None = None
27
+ parent: BitbucketCommentParentSchema | None = None
20
28
  inline: BitbucketCommentInlineSchema | None = None
21
29
  content: BitbucketCommentContentSchema
22
30
 
23
31
 
24
32
  class BitbucketGetPRCommentsQuerySchema(BaseModel):
25
- pagelen: int = 100
33
+ model_config = ConfigDict(populate_by_name=True)
34
+
35
+ page: int = 1
36
+ page_len: int = Field(alias="pagelen", default=100)
26
37
 
27
38
 
28
39
  class BitbucketGetPRCommentsResponseSchema(BaseModel):
40
+ model_config = ConfigDict(populate_by_name=True)
41
+
29
42
  size: int
30
43
  page: int | None = None
31
44
  next: str | None = None
32
45
  values: list[BitbucketPRCommentSchema]
33
- pagelen: int
46
+ page_len: int = Field(alias="pagelen")
47
+
48
+
49
+ class BitbucketParentSchema(BaseModel):
50
+ id: int
34
51
 
35
52
 
36
53
  class BitbucketCreatePRCommentRequestSchema(BaseModel):
54
+ parent: BitbucketParentSchema | None = None
37
55
  inline: BitbucketCommentInlineSchema | None = None
38
56
  content: BitbucketCommentContentSchema
39
57
 
40
58
 
41
59
  class BitbucketCreatePRCommentResponseSchema(BaseModel):
42
60
  id: int
61
+ parent: BitbucketParentSchema | None = None
43
62
  inline: BitbucketCommentInlineSchema | None = None
44
63
  content: BitbucketCommentContentSchema
@@ -1,4 +1,4 @@
1
- from pydantic import BaseModel
1
+ from pydantic import BaseModel, Field, ConfigDict
2
2
 
3
3
 
4
4
  class BitbucketPRFilePathSchema(BaseModel):
@@ -14,12 +14,17 @@ class BitbucketPRFileSchema(BaseModel):
14
14
 
15
15
 
16
16
  class BitbucketGetPRFilesQuerySchema(BaseModel):
17
- pagelen: int = 100
17
+ model_config = ConfigDict(populate_by_name=True)
18
+
19
+ page: int = 1
20
+ page_len: int = Field(alias="pagelen", default=100)
18
21
 
19
22
 
20
23
  class BitbucketGetPRFilesResponseSchema(BaseModel):
24
+ model_config = ConfigDict(populate_by_name=True)
25
+
21
26
  size: int
22
27
  page: int | None = None
23
28
  next: str | None = None
24
29
  values: list[BitbucketPRFileSchema]
25
- pagelen: int
30
+ page_len: int = Field(alias="pagelen")
@@ -1,10 +1,6 @@
1
1
  from pydantic import BaseModel, Field
2
2
 
3
-
4
- class BitbucketUserSchema(BaseModel):
5
- uuid: str
6
- nickname: str
7
- display_name: str
3
+ from ai_review.clients.bitbucket.pr.schema.user import BitbucketUserSchema
8
4
 
9
5
 
10
6
  class BitbucketBranchSchema(BaseModel):
@@ -0,0 +1,7 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class BitbucketUserSchema(BaseModel):
5
+ uuid: str
6
+ nickname: str
7
+ display_name: str
@@ -0,0 +1,6 @@
1
+ from httpx import Response
2
+
3
+
4
+ def bitbucket_has_next_page(response: Response) -> bool:
5
+ data = response.json()
6
+ return bool(data.get("next"))
@@ -1,25 +1,34 @@
1
1
  from httpx import Response, QueryParams
2
2
 
3
3
  from ai_review.clients.github.pr.schema.comments import (
4
+ GitHubPRCommentSchema,
5
+ GitHubIssueCommentSchema,
4
6
  GitHubGetPRCommentsQuerySchema,
5
7
  GitHubGetPRCommentsResponseSchema,
8
+ GitHubGetIssueCommentsResponseSchema,
6
9
  GitHubCreateIssueCommentRequestSchema,
7
10
  GitHubCreateIssueCommentResponseSchema,
11
+ GitHubCreateReviewReplyRequestSchema,
8
12
  GitHubCreateReviewCommentRequestSchema,
9
13
  GitHubCreateReviewCommentResponseSchema
10
14
  )
11
15
  from ai_review.clients.github.pr.schema.files import (
16
+ GitHubPRFileSchema,
12
17
  GitHubGetPRFilesQuerySchema,
13
18
  GitHubGetPRFilesResponseSchema
14
19
  )
15
20
  from ai_review.clients.github.pr.schema.pull_request import GitHubGetPRResponseSchema
16
21
  from ai_review.clients.github.pr.schema.reviews import (
22
+ GitHubPRReviewSchema,
17
23
  GitHubGetPRReviewsQuerySchema,
18
24
  GitHubGetPRReviewsResponseSchema
19
25
  )
20
26
  from ai_review.clients.github.pr.types import GitHubPullRequestsHTTPClientProtocol
27
+ from ai_review.clients.github.tools import github_has_next_page
28
+ from ai_review.config import settings
21
29
  from ai_review.libs.http.client import HTTPClient
22
30
  from ai_review.libs.http.handlers import HTTPClientError, handle_http_error
31
+ from ai_review.libs.http.paginate import paginate
23
32
 
24
33
 
25
34
  class GitHubPullRequestsHTTPClientError(HTTPClientError):
@@ -70,6 +79,19 @@ class GitHubPullRequestsHTTPClient(HTTPClient, GitHubPullRequestsHTTPClientProto
70
79
  query=QueryParams(**query.model_dump())
71
80
  )
72
81
 
82
+ @handle_http_error(client="GitHubPullRequestsHTTPClient", exception=GitHubPullRequestsHTTPClientError)
83
+ async def create_review_reply_api(
84
+ self,
85
+ owner: str,
86
+ repo: str,
87
+ pull_number: str,
88
+ request: GitHubCreateReviewReplyRequestSchema,
89
+ ) -> Response:
90
+ return await self.post(
91
+ f"/repos/{owner}/{repo}/pulls/{pull_number}/comments",
92
+ json=request.model_dump(),
93
+ )
94
+
73
95
  @handle_http_error(client="GitHubPullRequestsHTTPClient", exception=GitHubPullRequestsHTTPClientError)
74
96
  async def create_review_comment_api(
75
97
  self,
@@ -114,24 +136,87 @@ class GitHubPullRequestsHTTPClient(HTTPClient, GitHubPullRequestsHTTPClientProto
114
136
  return GitHubGetPRResponseSchema.model_validate_json(response.text)
115
137
 
116
138
  async def get_files(self, owner: str, repo: str, pull_number: str) -> GitHubGetPRFilesResponseSchema:
117
- query = GitHubGetPRFilesQuerySchema(per_page=100)
118
- response = await self.get_files_api(owner, repo, pull_number, query)
119
- return GitHubGetPRFilesResponseSchema.model_validate_json(response.text)
139
+ async def fetch_page(page: int) -> Response:
140
+ query = GitHubGetPRFilesQuerySchema(page=page, per_page=settings.vcs.pagination.per_page)
141
+ return await self.get_files_api(owner, repo, pull_number, query)
142
+
143
+ def extract_items(response: Response) -> list[GitHubPRFileSchema]:
144
+ result = GitHubGetPRFilesResponseSchema.model_validate_json(response.text)
145
+ return result.root
146
+
147
+ items = await paginate(
148
+ max_pages=settings.vcs.pagination.max_pages,
149
+ fetch_page=fetch_page,
150
+ extract_items=extract_items,
151
+ has_next_page=github_has_next_page
152
+ )
153
+ return GitHubGetPRFilesResponseSchema(root=items)
120
154
 
121
- async def get_issue_comments(self, owner: str, repo: str, issue_number: str) -> GitHubGetPRCommentsResponseSchema:
122
- query = GitHubGetPRCommentsQuerySchema(per_page=100)
123
- response = await self.get_issue_comments_api(owner, repo, issue_number, query)
124
- return GitHubGetPRCommentsResponseSchema.model_validate_json(response.text)
155
+ async def get_issue_comments(
156
+ self,
157
+ owner: str,
158
+ repo: str,
159
+ issue_number: str
160
+ ) -> GitHubGetIssueCommentsResponseSchema:
161
+ async def fetch_page(page: int) -> Response:
162
+ query = GitHubGetPRCommentsQuerySchema(page=page, per_page=settings.vcs.pagination.per_page)
163
+ return await self.get_issue_comments_api(owner, repo, issue_number, query)
164
+
165
+ def extract_items(response: Response) -> list[GitHubIssueCommentSchema]:
166
+ result = GitHubGetIssueCommentsResponseSchema.model_validate_json(response.text)
167
+ return result.root
168
+
169
+ items = await paginate(
170
+ max_pages=settings.vcs.pagination.max_pages,
171
+ fetch_page=fetch_page,
172
+ extract_items=extract_items,
173
+ has_next_page=github_has_next_page
174
+ )
175
+ return GitHubGetIssueCommentsResponseSchema(root=items)
125
176
 
126
177
  async def get_review_comments(self, owner: str, repo: str, pull_number: str) -> GitHubGetPRCommentsResponseSchema:
127
- query = GitHubGetPRCommentsQuerySchema(per_page=100)
128
- response = await self.get_review_comments_api(owner, repo, pull_number, query)
129
- return GitHubGetPRCommentsResponseSchema.model_validate_json(response.text)
178
+ async def fetch_page(page: int) -> Response:
179
+ query = GitHubGetPRCommentsQuerySchema(page=page, per_page=settings.vcs.pagination.per_page)
180
+ return await self.get_review_comments_api(owner, repo, pull_number, query)
181
+
182
+ def extract_items(response: Response) -> list[GitHubPRCommentSchema]:
183
+ result = GitHubGetPRCommentsResponseSchema.model_validate_json(response.text)
184
+ return result.root
185
+
186
+ items = await paginate(
187
+ max_pages=settings.vcs.pagination.max_pages,
188
+ fetch_page=fetch_page,
189
+ extract_items=extract_items,
190
+ has_next_page=github_has_next_page
191
+ )
192
+ return GitHubGetPRCommentsResponseSchema(root=items)
130
193
 
131
194
  async def get_reviews(self, owner: str, repo: str, pull_number: str) -> GitHubGetPRReviewsResponseSchema:
132
- query = GitHubGetPRReviewsQuerySchema(per_page=100)
133
- response = await self.get_reviews_api(owner, repo, pull_number, query)
134
- return GitHubGetPRReviewsResponseSchema.model_validate_json(response.text)
195
+ async def fetch_page(page: int) -> Response:
196
+ query = GitHubGetPRReviewsQuerySchema(page=page, per_page=settings.vcs.pagination.per_page)
197
+ return await self.get_reviews_api(owner, repo, pull_number, query)
198
+
199
+ def extract_items(response: Response) -> list[GitHubPRReviewSchema]:
200
+ result = GitHubGetPRReviewsResponseSchema.model_validate_json(response.text)
201
+ return result.root
202
+
203
+ items = await paginate(
204
+ max_pages=settings.vcs.pagination.max_pages,
205
+ fetch_page=fetch_page,
206
+ extract_items=extract_items,
207
+ has_next_page=github_has_next_page
208
+ )
209
+ return GitHubGetPRReviewsResponseSchema(root=items)
210
+
211
+ async def create_review_reply(
212
+ self,
213
+ owner: str,
214
+ repo: str,
215
+ pull_number: str,
216
+ request: GitHubCreateReviewReplyRequestSchema,
217
+ ) -> GitHubCreateReviewCommentResponseSchema:
218
+ response = await self.create_review_reply_api(owner, repo, pull_number, request)
219
+ return GitHubCreateReviewCommentResponseSchema.model_validate_json(response.text)
135
220
 
136
221
  async def create_review_comment(
137
222
  self,
@@ -1,21 +1,38 @@
1
1
  from pydantic import BaseModel, RootModel
2
2
 
3
+ from ai_review.clients.github.pr.schema.user import GitHubUserSchema
4
+
5
+
6
+ class GitHubIssueCommentSchema(BaseModel):
7
+ """Represents a top-level comment in a PR discussion (issue-level)."""
8
+ id: int
9
+ body: str
10
+ user: GitHubUserSchema | None = None
11
+
3
12
 
4
13
  class GitHubPRCommentSchema(BaseModel):
14
+ """Represents an inline code review comment on a specific line in a PR."""
5
15
  id: int
6
16
  body: str
7
17
  path: str | None = None
8
18
  line: int | None = None
19
+ user: GitHubUserSchema | None = None
20
+ in_reply_to_id: int | None = None
9
21
 
10
22
 
11
23
  class GitHubGetPRCommentsQuerySchema(BaseModel):
12
- per_page: int
24
+ page: int = 1
25
+ per_page: int = 100
13
26
 
14
27
 
15
28
  class GitHubGetPRCommentsResponseSchema(RootModel[list[GitHubPRCommentSchema]]):
16
29
  root: list[GitHubPRCommentSchema]
17
30
 
18
31
 
32
+ class GitHubGetIssueCommentsResponseSchema(RootModel[list[GitHubIssueCommentSchema]]):
33
+ root: list[GitHubIssueCommentSchema]
34
+
35
+
19
36
  class GitHubCreateIssueCommentRequestSchema(BaseModel):
20
37
  body: str
21
38
 
@@ -25,6 +42,11 @@ class GitHubCreateIssueCommentResponseSchema(BaseModel):
25
42
  body: str
26
43
 
27
44
 
45
+ class GitHubCreateReviewReplyRequestSchema(BaseModel):
46
+ body: str
47
+ in_reply_to: int
48
+
49
+
28
50
  class GitHubCreateReviewCommentRequestSchema(BaseModel):
29
51
  body: str
30
52
  path: str
@@ -9,7 +9,8 @@ class GitHubPRFileSchema(BaseModel):
9
9
 
10
10
 
11
11
  class GitHubGetPRFilesQuerySchema(BaseModel):
12
- per_page: int
12
+ page: int = 1
13
+ per_page: int = 100
13
14
 
14
15
 
15
16
  class GitHubGetPRFilesResponseSchema(RootModel[list[GitHubPRFileSchema]]):
@@ -1,9 +1,6 @@
1
1
  from pydantic import BaseModel, Field
2
2
 
3
-
4
- class GitHubUserSchema(BaseModel):
5
- id: int
6
- login: str
3
+ from ai_review.clients.github.pr.schema.user import GitHubUserSchema
7
4
 
8
5
 
9
6
  class GitHubLabelSchema(BaseModel):
@@ -10,7 +10,8 @@ class GitHubPRReviewSchema(BaseModel):
10
10
 
11
11
 
12
12
  class GitHubGetPRReviewsQuerySchema(BaseModel):
13
- per_page: int
13
+ page: int = 1
14
+ per_page: int = 100
14
15
 
15
16
 
16
17
  class GitHubGetPRReviewsResponseSchema(RootModel[list[GitHubPRReviewSchema]]):
@@ -0,0 +1,6 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class GitHubUserSchema(BaseModel):
5
+ id: int | None = None
6
+ login: str
@@ -2,7 +2,9 @@ from typing import Protocol
2
2
 
3
3
  from ai_review.clients.github.pr.schema.comments import (
4
4
  GitHubGetPRCommentsResponseSchema,
5
+ GitHubGetIssueCommentsResponseSchema,
5
6
  GitHubCreateIssueCommentResponseSchema,
7
+ GitHubCreateReviewReplyRequestSchema,
6
8
  GitHubCreateReviewCommentResponseSchema,
7
9
  GitHubCreateReviewCommentRequestSchema,
8
10
  )
@@ -21,7 +23,7 @@ class GitHubPullRequestsHTTPClientProtocol(Protocol):
21
23
  owner: str,
22
24
  repo: str,
23
25
  issue_number: str
24
- ) -> GitHubGetPRCommentsResponseSchema: ...
26
+ ) -> GitHubGetIssueCommentsResponseSchema: ...
25
27
 
26
28
  async def get_review_comments(
27
29
  self,
@@ -32,6 +34,14 @@ class GitHubPullRequestsHTTPClientProtocol(Protocol):
32
34
 
33
35
  async def get_reviews(self, owner: str, repo: str, pull_number: str) -> GitHubGetPRReviewsResponseSchema: ...
34
36
 
37
+ async def create_review_reply(
38
+ self,
39
+ owner: str,
40
+ repo: str,
41
+ comment_id: str,
42
+ request: GitHubCreateReviewReplyRequestSchema,
43
+ ) -> GitHubCreateReviewCommentResponseSchema: ...
44
+
35
45
  async def create_review_comment(
36
46
  self,
37
47
  owner: str,
@@ -0,0 +1,6 @@
1
+ from httpx import Response
2
+
3
+
4
+ def github_has_next_page(response: Response) -> bool:
5
+ link_header = response.headers.get("Link")
6
+ return (link_header is not None) and ('rel="next"' in link_header)