devcommit 0.1.5.5__tar.gz → 0.1.5.7__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.
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/PKG-INFO +29 -5
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/README.md +28 -4
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/app/ai_providers.py +47 -12
- devcommit-0.1.5.7/devcommit/app/changelog.py +378 -0
- devcommit-0.1.5.7/devcommit/app/model_catalog.py +246 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/create_config.py +10 -1
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/main.py +45 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/utils/git.py +44 -18
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/utils/parser.py +24 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/pyproject.toml +2 -2
- devcommit-0.1.5.5/devcommit/app/changelog.py +0 -96
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/COPYING +0 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/__init__.py +0 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/__version__.py +0 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/app/__init__.py +0 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/app/gemini_ai.py +0 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/app/prompt.py +0 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/utils/__init__.py +0 -0
- {devcommit-0.1.5.5 → devcommit-0.1.5.7}/devcommit/utils/logger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devcommit
|
|
3
|
-
Version: 0.1.5.
|
|
3
|
+
Version: 0.1.5.7
|
|
4
4
|
Summary: AI-powered git commit message generator
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -782,6 +782,7 @@ A command-line AI tool for autocommits.
|
|
|
782
782
|
# GEMINI_MODEL / OPENAI_MODEL / GROQ_MODEL / OPENROUTER_MODEL / ANTHROPIC_MODEL / OLLAMA_MODEL / CUSTOM_MODEL
|
|
783
783
|
MODEL_NAME = gemini-2.5-flash
|
|
784
784
|
COMMIT_MODE = auto
|
|
785
|
+
CHANGELOG_MODE = timestamped
|
|
785
786
|
EOF
|
|
786
787
|
```
|
|
787
788
|
|
|
@@ -796,6 +797,7 @@ A command-line AI tool for autocommits.
|
|
|
796
797
|
COMMIT_TYPE = conventional
|
|
797
798
|
MODEL_NAME = gemini-2.0-flash-exp
|
|
798
799
|
COMMIT_MODE = auto
|
|
800
|
+
CHANGELOG_MODE = timestamped
|
|
799
801
|
EOF
|
|
800
802
|
```
|
|
801
803
|
|
|
@@ -1150,8 +1152,11 @@ devcommit --stageAll --changelog --files src/
|
|
|
1150
1152
|
|
|
1151
1153
|
- **With `--stageAll`**: Changelog is generated from unstaged changes **before** staging
|
|
1152
1154
|
- **Without `--stageAll`**: Changelog is generated from the last commit **after** committing
|
|
1153
|
-
-
|
|
1154
|
-
-
|
|
1155
|
+
- Storage mode is controlled by `CHANGELOG_MODE`:
|
|
1156
|
+
- `timestamped` (default): new file per run in `changelogs/<branch>/<year>/<month>/<day>/<time>.md`
|
|
1157
|
+
- `branch`: one file per branch, updated in place at `changelogs/<branch>.md`
|
|
1158
|
+
- Default base directory is `changelogs/` (configurable via `CHANGELOG_DIR` in `.dcommit`)
|
|
1159
|
+
- Empty sections are automatically removed (including empty `## [Unreleased]`)
|
|
1155
1160
|
- Uses Keep a Changelog format with AI-generated content
|
|
1156
1161
|
|
|
1157
1162
|
**Example workflow:**
|
|
@@ -1163,7 +1168,9 @@ devcommit --stageAll --changelog --files src/
|
|
|
1163
1168
|
# Stage all changes and generate changelog before committing
|
|
1164
1169
|
devcommit --stageAll --changelog
|
|
1165
1170
|
|
|
1166
|
-
# The changelog file is created
|
|
1171
|
+
# The changelog file is created based on CHANGELOG_MODE
|
|
1172
|
+
# timestamped: changelogs/<branch>/<year>/<month>/<day>/<time>.md
|
|
1173
|
+
# branch: changelogs/<branch>.md
|
|
1167
1174
|
# Then changes are staged and committed
|
|
1168
1175
|
```
|
|
1169
1176
|
|
|
@@ -1177,6 +1184,8 @@ devcommit --stageAll --changelog
|
|
|
1177
1184
|
- `--files` or `-f`: Stage and commit specific files or folders (can specify multiple)
|
|
1178
1185
|
- `--push` or `-p`: Push commits to remote after committing
|
|
1179
1186
|
- `--changelog` or `-c`: Generate changelog file from changes
|
|
1187
|
+
- `--models`: Fetch and list models from the configured `AI_PROVIDER`
|
|
1188
|
+
- `--free` / `--paid`: With `--models`, limit OpenRouter results to free or paid models
|
|
1180
1189
|
|
|
1181
1190
|
### Examples
|
|
1182
1191
|
|
|
@@ -1255,6 +1264,19 @@ export OPENROUTER_MODEL='meta-llama/llama-3.3-70b-instruct:free'
|
|
|
1255
1264
|
devcommit
|
|
1256
1265
|
```
|
|
1257
1266
|
|
|
1267
|
+
To fetch the live model catalogue for your configured provider without opening a browser:
|
|
1268
|
+
|
|
1269
|
+
```bash
|
|
1270
|
+
AI_PROVIDER=openrouter devcommit --models
|
|
1271
|
+
|
|
1272
|
+
# Only free OpenRouter models
|
|
1273
|
+
AI_PROVIDER=openrouter devcommit --models --free
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1276
|
+
For OpenRouter, the table identifies free and paid models and shows their live token prices. For other providers, it lists the models accessible with that provider's configured API key; Ollama lists models installed locally. Copy an ID into the matching provider model setting, such as `OPENROUTER_MODEL`.
|
|
1277
|
+
|
|
1278
|
+
Set `REASONING_EFFORT=none` to disable reasoning where the selected model supports it and favor faster commit messages. The default is `auto`; `low`, `medium`, `high`, `xhigh`, and `max` are also accepted where supported.
|
|
1279
|
+
|
|
1258
1280
|
**Popular free models on OpenRouter (add `:free` suffix):**
|
|
1259
1281
|
|
|
1260
1282
|
**Recommended Models:**
|
|
@@ -1356,9 +1378,11 @@ All configuration can be set via **environment variables** or **`.dcommit` file*
|
|
|
1356
1378
|
| `MAX_NO` | Number of commit message suggestions | `1` | Any positive integer |
|
|
1357
1379
|
| `COMMIT_TYPE` | Style of commit messages | `general` | `general`, `conventional`, etc. |
|
|
1358
1380
|
| `COMMIT_MODE` | Default commit strategy | `auto` | `auto`, `directory`, `global`, `related` |
|
|
1359
|
-
| `
|
|
1381
|
+
| `REASONING_EFFORT` | Reasoning effort for supported models | `auto` | `auto`, `none`, `low`, `medium`, `high`, `xhigh`, `max` |
|
|
1382
|
+
| `EXCLUDE_FILES` | Files to exclude from diff | `package-lock.json, pnpm-lock.yaml, yarn.lock, *.lock` | Comma-separated patterns or absolute paths within one repo |
|
|
1360
1383
|
| `MAX_TOKENS` | Maximum tokens for AI response | `8192` | Any positive integer |
|
|
1361
1384
|
| `CHANGELOG_DIR` | Directory for changelog files | `changelogs` | Any directory path |
|
|
1385
|
+
| `CHANGELOG_MODE` | Changelog file strategy | `timestamped` | `timestamped`, `branch` |
|
|
1362
1386
|
|
|
1363
1387
|
### Configuration Priority
|
|
1364
1388
|
|
|
@@ -77,6 +77,7 @@ A command-line AI tool for autocommits.
|
|
|
77
77
|
# GEMINI_MODEL / OPENAI_MODEL / GROQ_MODEL / OPENROUTER_MODEL / ANTHROPIC_MODEL / OLLAMA_MODEL / CUSTOM_MODEL
|
|
78
78
|
MODEL_NAME = gemini-2.5-flash
|
|
79
79
|
COMMIT_MODE = auto
|
|
80
|
+
CHANGELOG_MODE = timestamped
|
|
80
81
|
EOF
|
|
81
82
|
```
|
|
82
83
|
|
|
@@ -91,6 +92,7 @@ A command-line AI tool for autocommits.
|
|
|
91
92
|
COMMIT_TYPE = conventional
|
|
92
93
|
MODEL_NAME = gemini-2.0-flash-exp
|
|
93
94
|
COMMIT_MODE = auto
|
|
95
|
+
CHANGELOG_MODE = timestamped
|
|
94
96
|
EOF
|
|
95
97
|
```
|
|
96
98
|
|
|
@@ -445,8 +447,11 @@ devcommit --stageAll --changelog --files src/
|
|
|
445
447
|
|
|
446
448
|
- **With `--stageAll`**: Changelog is generated from unstaged changes **before** staging
|
|
447
449
|
- **Without `--stageAll`**: Changelog is generated from the last commit **after** committing
|
|
448
|
-
-
|
|
449
|
-
-
|
|
450
|
+
- Storage mode is controlled by `CHANGELOG_MODE`:
|
|
451
|
+
- `timestamped` (default): new file per run in `changelogs/<branch>/<year>/<month>/<day>/<time>.md`
|
|
452
|
+
- `branch`: one file per branch, updated in place at `changelogs/<branch>.md`
|
|
453
|
+
- Default base directory is `changelogs/` (configurable via `CHANGELOG_DIR` in `.dcommit`)
|
|
454
|
+
- Empty sections are automatically removed (including empty `## [Unreleased]`)
|
|
450
455
|
- Uses Keep a Changelog format with AI-generated content
|
|
451
456
|
|
|
452
457
|
**Example workflow:**
|
|
@@ -458,7 +463,9 @@ devcommit --stageAll --changelog --files src/
|
|
|
458
463
|
# Stage all changes and generate changelog before committing
|
|
459
464
|
devcommit --stageAll --changelog
|
|
460
465
|
|
|
461
|
-
# The changelog file is created
|
|
466
|
+
# The changelog file is created based on CHANGELOG_MODE
|
|
467
|
+
# timestamped: changelogs/<branch>/<year>/<month>/<day>/<time>.md
|
|
468
|
+
# branch: changelogs/<branch>.md
|
|
462
469
|
# Then changes are staged and committed
|
|
463
470
|
```
|
|
464
471
|
|
|
@@ -472,6 +479,8 @@ devcommit --stageAll --changelog
|
|
|
472
479
|
- `--files` or `-f`: Stage and commit specific files or folders (can specify multiple)
|
|
473
480
|
- `--push` or `-p`: Push commits to remote after committing
|
|
474
481
|
- `--changelog` or `-c`: Generate changelog file from changes
|
|
482
|
+
- `--models`: Fetch and list models from the configured `AI_PROVIDER`
|
|
483
|
+
- `--free` / `--paid`: With `--models`, limit OpenRouter results to free or paid models
|
|
475
484
|
|
|
476
485
|
### Examples
|
|
477
486
|
|
|
@@ -550,6 +559,19 @@ export OPENROUTER_MODEL='meta-llama/llama-3.3-70b-instruct:free'
|
|
|
550
559
|
devcommit
|
|
551
560
|
```
|
|
552
561
|
|
|
562
|
+
To fetch the live model catalogue for your configured provider without opening a browser:
|
|
563
|
+
|
|
564
|
+
```bash
|
|
565
|
+
AI_PROVIDER=openrouter devcommit --models
|
|
566
|
+
|
|
567
|
+
# Only free OpenRouter models
|
|
568
|
+
AI_PROVIDER=openrouter devcommit --models --free
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
For OpenRouter, the table identifies free and paid models and shows their live token prices. For other providers, it lists the models accessible with that provider's configured API key; Ollama lists models installed locally. Copy an ID into the matching provider model setting, such as `OPENROUTER_MODEL`.
|
|
572
|
+
|
|
573
|
+
Set `REASONING_EFFORT=none` to disable reasoning where the selected model supports it and favor faster commit messages. The default is `auto`; `low`, `medium`, `high`, `xhigh`, and `max` are also accepted where supported.
|
|
574
|
+
|
|
553
575
|
**Popular free models on OpenRouter (add `:free` suffix):**
|
|
554
576
|
|
|
555
577
|
**Recommended Models:**
|
|
@@ -651,9 +673,11 @@ All configuration can be set via **environment variables** or **`.dcommit` file*
|
|
|
651
673
|
| `MAX_NO` | Number of commit message suggestions | `1` | Any positive integer |
|
|
652
674
|
| `COMMIT_TYPE` | Style of commit messages | `general` | `general`, `conventional`, etc. |
|
|
653
675
|
| `COMMIT_MODE` | Default commit strategy | `auto` | `auto`, `directory`, `global`, `related` |
|
|
654
|
-
| `
|
|
676
|
+
| `REASONING_EFFORT` | Reasoning effort for supported models | `auto` | `auto`, `none`, `low`, `medium`, `high`, `xhigh`, `max` |
|
|
677
|
+
| `EXCLUDE_FILES` | Files to exclude from diff | `package-lock.json, pnpm-lock.yaml, yarn.lock, *.lock` | Comma-separated patterns or absolute paths within one repo |
|
|
655
678
|
| `MAX_TOKENS` | Maximum tokens for AI response | `8192` | Any positive integer |
|
|
656
679
|
| `CHANGELOG_DIR` | Directory for changelog files | `changelogs` | Any directory path |
|
|
680
|
+
| `CHANGELOG_MODE` | Changelog file strategy | `timestamped` | `timestamped`, `branch` |
|
|
657
681
|
|
|
658
682
|
### Configuration Priority
|
|
659
683
|
|
|
@@ -34,6 +34,19 @@ except ImportError:
|
|
|
34
34
|
sys.stderr = _stderr
|
|
35
35
|
_devnull.close()
|
|
36
36
|
|
|
37
|
+
REASONING_EFFORTS = {"auto", "none", "low", "medium", "high", "xhigh", "max"}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def normalize_reasoning_effort(value: str) -> str:
|
|
41
|
+
effort = value.lower()
|
|
42
|
+
if effort not in REASONING_EFFORTS:
|
|
43
|
+
raise ValueError("REASONING_EFFORT must be auto, none, low, medium, high, xhigh, or max")
|
|
44
|
+
return effort
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def reasoning_extra_body(effort: str) -> dict:
|
|
48
|
+
return {} if effort == "auto" else {"reasoning_effort": effort}
|
|
49
|
+
|
|
37
50
|
|
|
38
51
|
class AIProvider(ABC):
|
|
39
52
|
"""Base class for AI providers"""
|
|
@@ -106,11 +119,12 @@ class GeminiProvider(AIProvider):
|
|
|
106
119
|
class OpenAIProvider(AIProvider):
|
|
107
120
|
"""OpenAI GPT provider"""
|
|
108
121
|
|
|
109
|
-
def __init__(self, api_key: str, model: str = "gpt-4o-mini"):
|
|
122
|
+
def __init__(self, api_key: str, model: str = "gpt-4o-mini", reasoning_effort: str = "auto"):
|
|
110
123
|
if not openai:
|
|
111
124
|
raise ImportError("openai not installed. Run: pip install openai")
|
|
112
125
|
self.client = openai.OpenAI(api_key=api_key)
|
|
113
126
|
self.model = model
|
|
127
|
+
self.reasoning_effort = normalize_reasoning_effort(reasoning_effort)
|
|
114
128
|
|
|
115
129
|
def generate_commit_message(
|
|
116
130
|
self, diff: str, prompt: str, max_tokens: int
|
|
@@ -123,6 +137,7 @@ class OpenAIProvider(AIProvider):
|
|
|
123
137
|
],
|
|
124
138
|
max_tokens=max_tokens,
|
|
125
139
|
temperature=0.7,
|
|
140
|
+
extra_body=reasoning_extra_body(self.reasoning_effort),
|
|
126
141
|
)
|
|
127
142
|
if not response or not response.choices:
|
|
128
143
|
raise ValueError("OpenAI returned empty response (no choices).")
|
|
@@ -132,13 +147,14 @@ class OpenAIProvider(AIProvider):
|
|
|
132
147
|
class GroqProvider(AIProvider):
|
|
133
148
|
"""Groq AI provider (OpenAI-compatible)"""
|
|
134
149
|
|
|
135
|
-
def __init__(self, api_key: str, model: str = "llama-3.3-70b-versatile"):
|
|
150
|
+
def __init__(self, api_key: str, model: str = "llama-3.3-70b-versatile", reasoning_effort: str = "auto"):
|
|
136
151
|
if not openai:
|
|
137
152
|
raise ImportError("openai not installed. Run: pip install openai")
|
|
138
153
|
self.client = openai.OpenAI(
|
|
139
154
|
api_key=api_key, base_url="https://api.groq.com/openai/v1"
|
|
140
155
|
)
|
|
141
156
|
self.model = model
|
|
157
|
+
self.reasoning_effort = normalize_reasoning_effort(reasoning_effort)
|
|
142
158
|
|
|
143
159
|
def generate_commit_message(
|
|
144
160
|
self, diff: str, prompt: str, max_tokens: int
|
|
@@ -151,6 +167,7 @@ class GroqProvider(AIProvider):
|
|
|
151
167
|
],
|
|
152
168
|
max_tokens=max_tokens,
|
|
153
169
|
temperature=0.7,
|
|
170
|
+
extra_body=reasoning_extra_body(self.reasoning_effort),
|
|
154
171
|
)
|
|
155
172
|
if not response or not response.choices:
|
|
156
173
|
raise ValueError("Groq returned empty response (no choices).")
|
|
@@ -164,6 +181,7 @@ class OpenRouterProvider(AIProvider):
|
|
|
164
181
|
self,
|
|
165
182
|
api_key: str,
|
|
166
183
|
model: str = "meta-llama/llama-3.3-70b-instruct:free",
|
|
184
|
+
reasoning_effort: str = "auto",
|
|
167
185
|
):
|
|
168
186
|
if not openai:
|
|
169
187
|
raise ImportError("openai not installed. Run: pip install openai")
|
|
@@ -176,6 +194,7 @@ class OpenRouterProvider(AIProvider):
|
|
|
176
194
|
},
|
|
177
195
|
)
|
|
178
196
|
self.model = model
|
|
197
|
+
self.reasoning_effort = normalize_reasoning_effort(reasoning_effort)
|
|
179
198
|
|
|
180
199
|
def generate_commit_message(
|
|
181
200
|
self, diff: str, prompt: str, max_tokens: int
|
|
@@ -188,7 +207,7 @@ class OpenRouterProvider(AIProvider):
|
|
|
188
207
|
],
|
|
189
208
|
max_tokens=max_tokens,
|
|
190
209
|
temperature=0.7,
|
|
191
|
-
extra_body={"transforms": ["middle-out"]},
|
|
210
|
+
extra_body={"transforms": ["middle-out"], **reasoning_extra_body(self.reasoning_effort)},
|
|
192
211
|
extra_headers={
|
|
193
212
|
"HTTP-Referer": "https://github.com/hordunlarmy/DevCommit",
|
|
194
213
|
"X-Title": "DevCommit",
|
|
@@ -207,23 +226,30 @@ class OpenRouterProvider(AIProvider):
|
|
|
207
226
|
class AnthropicProvider(AIProvider):
|
|
208
227
|
"""Anthropic Claude provider"""
|
|
209
228
|
|
|
210
|
-
def __init__(self, api_key: str, model: str = "claude-3-haiku-20240307"):
|
|
229
|
+
def __init__(self, api_key: str, model: str = "claude-3-haiku-20240307", reasoning_effort: str = "auto"):
|
|
211
230
|
if not anthropic:
|
|
212
231
|
raise ImportError(
|
|
213
232
|
"anthropic not installed. Run: pip install anthropic"
|
|
214
233
|
)
|
|
215
234
|
self.client = anthropic.Anthropic(api_key=api_key)
|
|
216
235
|
self.model = model
|
|
236
|
+
self.reasoning_effort = normalize_reasoning_effort(reasoning_effort)
|
|
217
237
|
|
|
218
238
|
def generate_commit_message(
|
|
219
239
|
self, diff: str, prompt: str, max_tokens: int
|
|
220
240
|
) -> str:
|
|
221
|
-
|
|
241
|
+
request = dict(
|
|
222
242
|
model=self.model,
|
|
223
243
|
max_tokens=max_tokens,
|
|
224
244
|
system=prompt,
|
|
225
245
|
messages=[{"role": "user", "content": diff}],
|
|
226
246
|
)
|
|
247
|
+
if self.reasoning_effort == "none":
|
|
248
|
+
request["thinking"] = {"type": "disabled"}
|
|
249
|
+
elif self.reasoning_effort != "auto":
|
|
250
|
+
request["thinking"] = {"type": "adaptive"}
|
|
251
|
+
request["output_config"] = {"effort": self.reasoning_effort}
|
|
252
|
+
message = self.client.messages.create(**request)
|
|
227
253
|
return message.content[0].text.strip()
|
|
228
254
|
|
|
229
255
|
|
|
@@ -231,7 +257,7 @@ class OllamaProvider(AIProvider):
|
|
|
231
257
|
"""Ollama local model provider"""
|
|
232
258
|
|
|
233
259
|
def __init__(
|
|
234
|
-
self, base_url: str = "http://localhost:11434", model: str = "llama3"
|
|
260
|
+
self, base_url: str = "http://localhost:11434", model: str = "llama3", reasoning_effort: str = "auto"
|
|
235
261
|
):
|
|
236
262
|
if not requests:
|
|
237
263
|
raise ImportError(
|
|
@@ -239,6 +265,7 @@ class OllamaProvider(AIProvider):
|
|
|
239
265
|
)
|
|
240
266
|
self.base_url = base_url.rstrip("/")
|
|
241
267
|
self.model = model
|
|
268
|
+
self.reasoning_effort = normalize_reasoning_effort(reasoning_effort)
|
|
242
269
|
|
|
243
270
|
def generate_commit_message(
|
|
244
271
|
self, diff: str, prompt: str, max_tokens: int
|
|
@@ -250,6 +277,8 @@ class OllamaProvider(AIProvider):
|
|
|
250
277
|
"stream": False,
|
|
251
278
|
"options": {"temperature": 0.7, "num_predict": max_tokens},
|
|
252
279
|
}
|
|
280
|
+
if self.reasoning_effort != "auto":
|
|
281
|
+
data["think"] = False if self.reasoning_effort == "none" else self.reasoning_effort
|
|
253
282
|
|
|
254
283
|
response = requests.post(url, json=data, timeout=60)
|
|
255
284
|
response.raise_for_status()
|
|
@@ -267,6 +296,7 @@ class CustomProvider(AIProvider):
|
|
|
267
296
|
api_url: str,
|
|
268
297
|
api_key: Optional[str] = None,
|
|
269
298
|
model: str = "default",
|
|
299
|
+
reasoning_effort: str = "auto",
|
|
270
300
|
):
|
|
271
301
|
if not openai:
|
|
272
302
|
raise ImportError("openai not installed. Run: pip install openai")
|
|
@@ -282,6 +312,7 @@ class CustomProvider(AIProvider):
|
|
|
282
312
|
api_key=api_key or "dummy-key", base_url=base_url
|
|
283
313
|
)
|
|
284
314
|
self.model = model
|
|
315
|
+
self.reasoning_effort = normalize_reasoning_effort(reasoning_effort)
|
|
285
316
|
|
|
286
317
|
def generate_commit_message(
|
|
287
318
|
self, diff: str, prompt: str, max_tokens: int
|
|
@@ -294,6 +325,7 @@ class CustomProvider(AIProvider):
|
|
|
294
325
|
],
|
|
295
326
|
max_tokens=max_tokens,
|
|
296
327
|
temperature=0.7,
|
|
328
|
+
extra_body=reasoning_extra_body(self.reasoning_effort),
|
|
297
329
|
)
|
|
298
330
|
if not response or not response.choices:
|
|
299
331
|
raise ValueError("Custom API returned empty response (no choices).")
|
|
@@ -304,6 +336,7 @@ def get_ai_provider(config) -> AIProvider:
|
|
|
304
336
|
"""Factory function to get the appropriate AI provider based on config"""
|
|
305
337
|
|
|
306
338
|
provider_name = config("AI_PROVIDER", default="gemini").lower()
|
|
339
|
+
reasoning_effort = config("REASONING_EFFORT", default="auto")
|
|
307
340
|
|
|
308
341
|
if provider_name == "gemini":
|
|
309
342
|
api_key = config("GEMINI_API_KEY", default=None)
|
|
@@ -313,6 +346,8 @@ def get_ai_provider(config) -> AIProvider:
|
|
|
313
346
|
model = config("GEMINI_MODEL", default=None) or config(
|
|
314
347
|
"MODEL_NAME", default="gemini-2.0-flash-exp"
|
|
315
348
|
)
|
|
349
|
+
if normalize_reasoning_effort(reasoning_effort) != "auto":
|
|
350
|
+
raise ValueError("REASONING_EFFORT is unsupported by the legacy Gemini SDK; use auto")
|
|
316
351
|
return GeminiProvider(api_key, model)
|
|
317
352
|
|
|
318
353
|
elif provider_name == "openai":
|
|
@@ -322,7 +357,7 @@ def get_ai_provider(config) -> AIProvider:
|
|
|
322
357
|
model = config("OPENAI_MODEL", default=None) or config(
|
|
323
358
|
"MODEL_NAME", default="gpt-4o-mini"
|
|
324
359
|
)
|
|
325
|
-
return OpenAIProvider(api_key, model)
|
|
360
|
+
return OpenAIProvider(api_key, model, reasoning_effort)
|
|
326
361
|
|
|
327
362
|
elif provider_name == "groq":
|
|
328
363
|
api_key = config("GROQ_API_KEY", default=None)
|
|
@@ -331,7 +366,7 @@ def get_ai_provider(config) -> AIProvider:
|
|
|
331
366
|
model = config("GROQ_MODEL", default=None) or config(
|
|
332
367
|
"MODEL_NAME", default="llama-3.3-70b-versatile"
|
|
333
368
|
)
|
|
334
|
-
return GroqProvider(api_key, model)
|
|
369
|
+
return GroqProvider(api_key, model, reasoning_effort)
|
|
335
370
|
|
|
336
371
|
elif provider_name == "openrouter":
|
|
337
372
|
api_key = config("OPENROUTER_API_KEY", default=None)
|
|
@@ -340,7 +375,7 @@ def get_ai_provider(config) -> AIProvider:
|
|
|
340
375
|
model = config("OPENROUTER_MODEL", default=None) or config(
|
|
341
376
|
"MODEL_NAME", default="meta-llama/llama-3.3-70b-instruct:free"
|
|
342
377
|
)
|
|
343
|
-
return OpenRouterProvider(api_key, model)
|
|
378
|
+
return OpenRouterProvider(api_key, model, reasoning_effort)
|
|
344
379
|
|
|
345
380
|
elif provider_name == "anthropic":
|
|
346
381
|
api_key = config("ANTHROPIC_API_KEY", default=None)
|
|
@@ -349,14 +384,14 @@ def get_ai_provider(config) -> AIProvider:
|
|
|
349
384
|
model = config("ANTHROPIC_MODEL", default=None) or config(
|
|
350
385
|
"MODEL_NAME", default="claude-3-haiku-20240307"
|
|
351
386
|
)
|
|
352
|
-
return AnthropicProvider(api_key, model)
|
|
387
|
+
return AnthropicProvider(api_key, model, reasoning_effort)
|
|
353
388
|
|
|
354
389
|
elif provider_name == "ollama":
|
|
355
390
|
base_url = config("OLLAMA_BASE_URL", default="http://localhost:11434")
|
|
356
391
|
model = config("OLLAMA_MODEL", default=None) or config(
|
|
357
392
|
"MODEL_NAME", default="llama3"
|
|
358
393
|
)
|
|
359
|
-
return OllamaProvider(base_url, model)
|
|
394
|
+
return OllamaProvider(base_url, model, reasoning_effort)
|
|
360
395
|
|
|
361
396
|
elif provider_name == "custom":
|
|
362
397
|
api_url = config("CUSTOM_API_URL", default=None)
|
|
@@ -366,7 +401,7 @@ def get_ai_provider(config) -> AIProvider:
|
|
|
366
401
|
model = config("CUSTOM_MODEL", default=None) or config(
|
|
367
402
|
"MODEL_NAME", default="default"
|
|
368
403
|
)
|
|
369
|
-
return CustomProvider(api_url, api_key, model)
|
|
404
|
+
return CustomProvider(api_url, api_key, model, reasoning_effort)
|
|
370
405
|
|
|
371
406
|
else:
|
|
372
407
|
raise ValueError(
|