Skip to content

Commit 66d0b41

Browse files
committed
✨ feat(ai): add reasoning support for compatible models
1 parent a4e3ec1 commit 66d0b41

File tree

4 files changed

+53
-11
lines changed

4 files changed

+53
-11
lines changed

tests/unit/test_commit.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ def test_generate_commit_with_ai_success(self, mock_settings, mock_template, moc
306306
mock_check.assert_called_once()
307307
mock_create_client.assert_called_once()
308308
mock_client.responses.parse.assert_called_once()
309+
_, kwargs = mock_client.responses.parse.call_args
310+
assert "reasoning" not in kwargs
309311

310312
@patch("tgit.commit._check_openai_availability")
311313
@patch("tgit.commit._create_openai_client")
@@ -319,6 +321,31 @@ def test_generate_commit_with_ai_failure(self, mock_console, mock_create_client,
319321
with pytest.raises(Exception):
320322
_generate_commit_with_ai("diff content", None, "main")
321323

324+
@patch("tgit.commit._check_openai_availability")
325+
@patch("tgit.commit._create_openai_client")
326+
@patch("tgit.commit.console")
327+
@patch("tgit.commit.commit_prompt_template")
328+
@patch("tgit.commit.settings")
329+
def test_generate_commit_with_ai_reasoning_model(self, mock_settings, mock_template, mock_console, mock_create_client, mock_check):
330+
"""Test reasoning effort is added for reasoning-capable models."""
331+
mock_client = Mock()
332+
mock_create_client.return_value = mock_client
333+
mock_template.render.return_value = "system prompt"
334+
mock_settings.model = "o1-mini"
335+
336+
mock_response = Mock()
337+
mock_commit_data = CommitData(type="fix", scope=None, msg="correct bug", is_breaking=False)
338+
mock_response.output_parsed = mock_commit_data
339+
mock_client.responses.parse.return_value = mock_response
340+
341+
result = _generate_commit_with_ai("diff content", None, "main")
342+
343+
assert result == mock_commit_data
344+
mock_check.assert_called_once()
345+
mock_create_client.assert_called_once()
346+
_, kwargs = mock_client.responses.parse.call_args
347+
assert kwargs["reasoning"] == {"effort": "minimal"}
348+
322349

323350
class TestGetAICommand:
324351
"""Test get_ai_command function."""

tgit/commit.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
import itertools
44
from dataclasses import dataclass
55
from pathlib import Path
6-
from typing import TYPE_CHECKING
6+
from typing import TYPE_CHECKING, Any
77

88
import click
99
import git
1010
from jinja2 import Environment, FileSystemLoader
1111
from pydantic import BaseModel
1212
from rich import get_console, print
1313

14-
from tgit.constants import DEFAULT_MODEL
14+
from tgit.constants import DEFAULT_MODEL, REASONING_MODEL_HINTS
1515
from tgit.shared import settings
1616
from tgit.utils import get_commit_command, run_command, type_emojis
1717

@@ -72,6 +72,14 @@ class CommitData(BaseModel):
7272
is_breaking: bool
7373

7474

75+
def _supports_reasoning(model: str) -> bool:
76+
"""Return True when the selected model supports reasoning parameters."""
77+
if not model:
78+
return False
79+
model_lower = model.lower()
80+
return any(hint in model_lower for hint in REASONING_MODEL_HINTS)
81+
82+
7583
def get_changed_files_from_status(repo: git.Repo) -> set[str]:
7684
"""获取所有变更的文件,包括重命名/移动的文件"""
7785
diff_name_status = repo.git.diff("--cached", "--name-status", "-M")
@@ -178,18 +186,24 @@ def _generate_commit_with_ai(diff: str, specified_type: str | None, current_bran
178186
)
179187

180188
with console.status("[bold green]Generating commit message...[/bold green]"):
181-
chat_completion = client.responses.parse(
182-
input=[
189+
model_name = settings.model or DEFAULT_MODEL
190+
request_kwargs: dict[str, Any] = {
191+
"input": [
183192
{
184193
"role": "system",
185194
"content": commit_prompt_template.render(**template_params.__dict__),
186195
},
187196
{"role": "user", "content": diff},
188197
],
189-
model=settings.model or DEFAULT_MODEL,
190-
reasoning={"effort": "minimal"},
191-
max_output_tokens=50,
192-
text_format=CommitData,
198+
"model": model_name,
199+
"max_output_tokens": 50,
200+
"text_format": CommitData,
201+
}
202+
if _supports_reasoning(model_name):
203+
request_kwargs["reasoning"] = {"effort": "minimal"}
204+
205+
chat_completion = client.responses.parse(
206+
**request_kwargs,
193207
)
194208

195209
return chat_completion.output_parsed

tgit/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
"""Global constants used across the TGIT project."""
22

33
DEFAULT_MODEL = "gpt-5-mini"
4+
REASONING_MODEL_HINTS = ("-reasoning", "o1", "o3")

uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)