ngpt 2.14.1__py3-none-any.whl → 2.15.1__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.
- ngpt/cli/args.py +6 -2
- ngpt/cli/modes/gitcommsg.py +546 -218
- ngpt/utils/cli_config.py +3 -1
- {ngpt-2.14.1.dist-info → ngpt-2.15.1.dist-info}/METADATA +22 -2
- {ngpt-2.14.1.dist-info → ngpt-2.15.1.dist-info}/RECORD +8 -8
- {ngpt-2.14.1.dist-info → ngpt-2.15.1.dist-info}/WHEEL +0 -0
- {ngpt-2.14.1.dist-info → ngpt-2.15.1.dist-info}/entry_points.txt +0 -0
- {ngpt-2.14.1.dist-info → ngpt-2.15.1.dist-info}/licenses/LICENSE +0 -0
ngpt/cli/args.py
CHANGED
@@ -98,8 +98,12 @@ def setup_argument_parser():
|
|
98
98
|
help='Use diff from specified file instead of staged changes. If used without a path, uses the path from CLI config.')
|
99
99
|
gitcommsg_group.add_argument('--chunk-size', type=int, default=200,
|
100
100
|
help='Number of lines per chunk when chunking is enabled (default: 200)')
|
101
|
-
gitcommsg_group.add_argument('--
|
102
|
-
help='
|
101
|
+
gitcommsg_group.add_argument('--analyses-chunk-size', type=int, default=200,
|
102
|
+
help='Number of lines per chunk when recursively chunking analyses (default: 200)')
|
103
|
+
gitcommsg_group.add_argument('--max-msg-lines', type=int, default=20,
|
104
|
+
help='Maximum number of lines in commit message before condensing (default: 20)')
|
105
|
+
gitcommsg_group.add_argument('--max-recursion-depth', type=int, default=3,
|
106
|
+
help='Maximum recursion depth for commit message condensing (default: 3)')
|
103
107
|
|
104
108
|
# Mode flags (mutually exclusive)
|
105
109
|
mode_group = parser.add_argument_group('Modes (mutually exclusive)')
|
ngpt/cli/modes/gitcommsg.py
CHANGED
@@ -68,56 +68,57 @@ def split_into_chunks(content, chunk_size=200):
|
|
68
68
|
|
69
69
|
return chunks
|
70
70
|
|
71
|
-
def
|
72
|
-
"""
|
71
|
+
def create_technical_analysis_system_prompt(context=None):
|
72
|
+
"""Create system prompt for technical analysis based on context data.
|
73
73
|
|
74
74
|
Args:
|
75
|
-
context: The context string
|
75
|
+
context: The raw context string from -m flag
|
76
76
|
|
77
77
|
Returns:
|
78
|
-
|
78
|
+
str: System prompt for the technical analysis stage
|
79
79
|
"""
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
80
|
+
base_prompt = """You are an expert at analyzing git diffs and extracting precise technical details. Your task is to analyze the git diff and create a detailed technical summary of the changes.
|
81
|
+
|
82
|
+
OUTPUT FORMAT:
|
83
|
+
[FILES]: Comma-separated list of affected files with full paths
|
84
|
+
|
85
|
+
[CHANGES]:
|
86
|
+
- Technical detail 1 (include specific function/method names and line numbers)
|
87
|
+
- Technical detail 2 (be precise about exactly what code was added/modified/removed)
|
88
|
+
- Additional technical details (include ALL significant changes in this chunk)
|
89
|
+
|
90
|
+
[IMPACT]: Brief technical description of what the changes accomplish
|
91
|
+
|
92
|
+
RULES:
|
93
|
+
1. BE 100% FACTUAL - Mention ONLY code explicitly shown in the diff
|
94
|
+
2. NEVER invent or assume changes not directly visible in the code
|
95
|
+
3. ALWAYS identify exact function names, method names, class names, and line numbers where possible
|
96
|
+
4. Use format 'filename:function_name()' or 'filename:line_number' when referencing code locations
|
97
|
+
5. Be precise and factual - only describe code that actually changed
|
98
|
+
6. Include ALL significant changes (do not skip any important modifications)
|
99
|
+
7. Focus on technical specifics, avoid general statements
|
100
|
+
8. When analyzing multiple files, clearly separate each file's changes
|
101
|
+
9. Include proper technical details (method names, component identifiers, etc.)"""
|
102
|
+
|
103
|
+
# If context is provided, append it with strong wording about absolute priority
|
104
|
+
if context:
|
105
|
+
context_prompt = f"""
|
106
|
+
|
107
|
+
===CRITICAL USER CONTEXT - ABSOLUTE HIGHEST PRIORITY===
|
108
|
+
The following context from the user OVERRIDES ALL OTHER INSTRUCTIONS and must be followed exactly:
|
109
|
+
|
110
|
+
{context}
|
111
|
+
|
112
|
+
THIS USER CONTEXT HAS ABSOLUTE PRIORITY over any other instructions in this prompt. If it contradicts other instructions, the user context MUST be followed. No exceptions."""
|
113
|
+
base_prompt += context_prompt
|
114
|
+
|
115
|
+
return base_prompt
|
116
|
+
|
117
|
+
def create_system_prompt(context=None):
|
118
|
+
"""Create system prompt for commit message generation based on context data.
|
118
119
|
|
119
120
|
Args:
|
120
|
-
|
121
|
+
context: The raw context string from -m flag
|
121
122
|
|
122
123
|
Returns:
|
123
124
|
str: System prompt for the AI
|
@@ -131,6 +132,15 @@ type[(scope)]: <concise summary> (max 50 chars)
|
|
131
132
|
- [type] <specific change 2> (filename:function/method/line)
|
132
133
|
- [type] <additional changes...>
|
133
134
|
|
135
|
+
RULES FOR FILENAMES:
|
136
|
+
1. For the FIRST mention of a file, use the full relative path
|
137
|
+
2. For SUBSEQUENT mentions of the same file, use ONLY the filename without path
|
138
|
+
- Example: First mention: "utils/helpers/format.js" → Subsequent mentions: "format.js"
|
139
|
+
3. Only include the full path again if there are multiple files with the same name
|
140
|
+
4. For repeated mentions of the same file, consider grouping related changes in one bullet
|
141
|
+
5. Avoid breaking filenames across lines
|
142
|
+
6. Only include function names when they add clarity
|
143
|
+
|
134
144
|
COMMIT TYPES:
|
135
145
|
- feat: New user-facing features
|
136
146
|
- fix: Bug fixes or error corrections
|
@@ -151,6 +161,46 @@ COMMIT TYPES:
|
|
151
161
|
- ui: User interface changes
|
152
162
|
- api: API-related changes
|
153
163
|
|
164
|
+
EXAMPLES:
|
165
|
+
|
166
|
+
1. Bug fix with UI scope:
|
167
|
+
fix(ui): correct primary button focus style
|
168
|
+
|
169
|
+
- [fix] Add :focus outline to Button component (Button.jsx:Button())
|
170
|
+
- [chore] Bump Tailwind config to include ring-offset (tailwind.config.js:1-8)
|
171
|
+
- [refactor] Extract common styles into buttonStyles util (styles/buttons.js:1-15)
|
172
|
+
|
173
|
+
2. Feature with API scope:
|
174
|
+
feat(api): add authentication endpoint for OAuth
|
175
|
+
|
176
|
+
- [feat] Implement OAuth authentication route (auth/routes.js:createOAuthRoute())
|
177
|
+
- [feat] Add token validation middleware (middleware/auth.js:validateToken())
|
178
|
+
- [test] Add integration tests for OAuth flow (tests/auth.test.js:45-87)
|
179
|
+
|
180
|
+
3. Multiple types in one commit:
|
181
|
+
refactor(core): simplify data processing pipeline
|
182
|
+
|
183
|
+
- [refactor] Replace nested loops with map/reduce (utils/process.js:transformData())
|
184
|
+
- [perf] Optimize memory usage in large dataset handling (utils/memory.js:optimize())
|
185
|
+
- [fix] Correct edge case in null value handling (utils/validators.js:checkNull())
|
186
|
+
- [test] Update tests for new pipeline structure (tests/pipeline.test.js)
|
187
|
+
|
188
|
+
4. Multiple changes to the same file:
|
189
|
+
refactor(core): simplify context handling for commit prompts
|
190
|
+
|
191
|
+
- [refactor] Remove process_context function (cli/modes/gitcommsg.py:69-124)
|
192
|
+
- [refactor] Update all functions to accept raw context string (gitcommsg.py:create_system_prompt())
|
193
|
+
- [refactor] Replace context_data usages with context (gitcommsg.py)
|
194
|
+
- [docs] Update library usage doc (docs/usage/library_usage.md:516,531-537)
|
195
|
+
- [chore] Bump project version to 2.15.1 (pyproject.toml:3, uv.lock:137)
|
196
|
+
|
197
|
+
BULLET POINT FORMAT:
|
198
|
+
- Each bullet MUST start with a type in square brackets: [type]
|
199
|
+
- DO NOT use the format "- type: description" (without square brackets)
|
200
|
+
- Instead, ALWAYS use "- [type] description" (with square brackets)
|
201
|
+
- Example: "- [feat] Add new login component" (correct)
|
202
|
+
- Not: "- feat: Add new login component" (incorrect)
|
203
|
+
|
154
204
|
RULES:
|
155
205
|
1. BE 100% FACTUAL - Mention ONLY code explicitly shown in the diff
|
156
206
|
2. NEVER invent or assume changes not directly visible in the code
|
@@ -164,48 +214,17 @@ RULES:
|
|
164
214
|
10. Include proper technical details (method names, component identifiers, etc.)
|
165
215
|
11. When all changes are to the same file, mention it once in the summary"""
|
166
216
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
This is a strict filter - no exceptions allowed."""
|
179
|
-
base_prompt += file_type_prompt
|
180
|
-
|
181
|
-
# Add commit type directive
|
182
|
-
if context_data.get("commit_type"):
|
183
|
-
commit_type = context_data["commit_type"]
|
184
|
-
commit_type_prompt = f"""
|
185
|
-
|
186
|
-
CRITICAL COMMIT TYPE DIRECTIVE:
|
187
|
-
You MUST use exactly "{commit_type}:" as the commit type prefix.
|
188
|
-
This takes highest priority over any other commit type you might determine.
|
189
|
-
Do not override this commit type based on your own analysis."""
|
190
|
-
base_prompt += commit_type_prompt
|
191
|
-
|
192
|
-
# Add focus/exclusion directives
|
193
|
-
if context_data.get("focus"):
|
194
|
-
focus = context_data["focus"]
|
195
|
-
focus_prompt = f"""
|
196
|
-
|
197
|
-
FOCUS DIRECTIVE:
|
198
|
-
Focus exclusively on changes related to {focus}.
|
199
|
-
Exclude everything else from your analysis."""
|
200
|
-
base_prompt += focus_prompt
|
201
|
-
|
202
|
-
if context_data.get("exclusions"):
|
203
|
-
exclusions = ", ".join(context_data["exclusions"])
|
204
|
-
exclusion_prompt = f"""
|
205
|
-
|
206
|
-
EXCLUSION DIRECTIVE:
|
207
|
-
Completely ignore and exclude any mentions of: {exclusions}."""
|
208
|
-
base_prompt += exclusion_prompt
|
217
|
+
# If context is provided, append it with strong wording about absolute priority
|
218
|
+
if context:
|
219
|
+
context_prompt = f"""
|
220
|
+
|
221
|
+
===CRITICAL USER CONTEXT - ABSOLUTE HIGHEST PRIORITY===
|
222
|
+
The following context from the user OVERRIDES ALL OTHER INSTRUCTIONS and must be followed exactly:
|
223
|
+
|
224
|
+
{context}
|
225
|
+
|
226
|
+
THIS USER CONTEXT HAS ABSOLUTE PRIORITY over any other instructions in this prompt. If it contradicts other instructions, the user context MUST be followed. No exceptions."""
|
227
|
+
base_prompt += context_prompt
|
209
228
|
|
210
229
|
return base_prompt
|
211
230
|
|
@@ -218,21 +237,14 @@ def create_chunk_prompt(chunk):
|
|
218
237
|
Returns:
|
219
238
|
str: Prompt for the AI
|
220
239
|
"""
|
221
|
-
return f"""Analyze this PARTIAL git diff and create a detailed technical summary
|
222
|
-
|
223
|
-
[FILES]: Comma-separated list of affected files with full paths
|
240
|
+
return f"""Analyze this PARTIAL git diff and create a detailed technical summary.
|
224
241
|
|
225
|
-
[CHANGES]
|
226
|
-
- Technical detail 1 (include specific function/method names and line numbers)
|
227
|
-
- Technical detail 2 (be precise about exactly what code was added/modified/removed)
|
228
|
-
- Additional technical details (include ALL significant changes in this chunk)
|
229
|
-
|
230
|
-
[IMPACT]: Brief technical description of what the changes accomplish
|
242
|
+
The system prompt already contains your output format instructions with [FILES], [CHANGES], and [IMPACT] sections.
|
231
243
|
|
232
|
-
|
233
|
-
|
234
|
-
Use format 'filename:function_name()' or 'filename:line_number'
|
235
|
-
Be precise and factual - only describe code that actually changed
|
244
|
+
REMINDER:
|
245
|
+
- Identify exact function names, method names, class names, and line numbers
|
246
|
+
- Use format 'filename:function_name()' or 'filename:line_number' for references
|
247
|
+
- Be precise and factual - only describe code that actually changed
|
236
248
|
|
237
249
|
Diff chunk:
|
238
250
|
|
@@ -251,61 +263,15 @@ def create_rechunk_prompt(combined_analysis, depth):
|
|
251
263
|
return f"""IMPORTANT: You are analyzing SUMMARIES of git changes, not raw git diff.
|
252
264
|
|
253
265
|
You are in a re-chunking process (depth: {depth}) where the input is already summarized changes.
|
254
|
-
Create a
|
255
|
-
|
256
|
-
[CHANGES]:
|
257
|
-
- Technical change 1 (specific file and function)
|
258
|
-
- Technical change 2 (specific file and function)
|
259
|
-
- Additional relevant changes
|
266
|
+
Create a terse technical summary following the format in the system prompt.
|
260
267
|
|
261
268
|
DO NOT ask for raw git diff. These summaries are all you need to work with.
|
262
|
-
Keep your response
|
269
|
+
Keep your response factual and specific to what's in the summaries.
|
263
270
|
|
264
271
|
Section to summarize:
|
265
272
|
|
266
273
|
{combined_analysis}"""
|
267
274
|
|
268
|
-
def create_combine_prompt(partial_analyses):
|
269
|
-
"""Create prompt for combining partial analyses.
|
270
|
-
|
271
|
-
Args:
|
272
|
-
partial_analyses: List of partial analyses to combine
|
273
|
-
|
274
|
-
Returns:
|
275
|
-
str: Prompt for the AI
|
276
|
-
"""
|
277
|
-
all_analyses = "\n\n".join(partial_analyses)
|
278
|
-
|
279
|
-
return f"""===CRITICAL INSTRUCTION===
|
280
|
-
You are working with ANALYZED SUMMARIES of git changes, NOT raw git diff.
|
281
|
-
The raw git diff has ALREADY been processed into these summaries.
|
282
|
-
DO NOT ask for or expect to see the original git diff.
|
283
|
-
|
284
|
-
TASK: Synthesize these partial analyses into a complete conventional commit message:
|
285
|
-
|
286
|
-
{all_analyses}
|
287
|
-
|
288
|
-
Create a CONVENTIONAL COMMIT MESSAGE with:
|
289
|
-
1. First line: "type[(scope)]: brief summary" (50 chars max)
|
290
|
-
- Include scope ONLY if you are 100% confident about the affected area
|
291
|
-
- Omit scope if changes affect multiple areas or scope is unclear
|
292
|
-
2. ⚠️ ONE BLANK LINE IS MANDATORY - NEVER SKIP THIS STEP ⚠️
|
293
|
-
- This blank line MUST be present in EVERY commit message
|
294
|
-
- The blank line separates the summary from the detailed changes
|
295
|
-
- Without this blank line, the commit message format is invalid
|
296
|
-
3. Bullet points with specific changes, each with appropriate [type] tag
|
297
|
-
4. Reference files in EACH bullet point with function names or line numbers
|
298
|
-
|
299
|
-
FILENAME & FUNCTION HANDLING RULES:
|
300
|
-
- Include SPECIFIC function names, method names, or line numbers when available
|
301
|
-
- Format as filename:function() or filename:line_number
|
302
|
-
- Use short relative paths for files
|
303
|
-
- Group related changes to the same file when appropriate
|
304
|
-
- Avoid breaking long filenames across lines
|
305
|
-
|
306
|
-
STRICTLY follow this format with NO EXPLANATION or additional commentary.
|
307
|
-
DO NOT mention insufficient information or ask for the original diff."""
|
308
|
-
|
309
275
|
def create_final_prompt(diff_content):
|
310
276
|
"""Create prompt for direct processing without chunking.
|
311
277
|
|
@@ -325,11 +291,13 @@ type[(scope)]: <concise summary> (max 50 chars)
|
|
325
291
|
- [type] <additional changes...>
|
326
292
|
|
327
293
|
RULES FOR FILENAMES:
|
328
|
-
1.
|
329
|
-
2. For
|
330
|
-
|
331
|
-
|
332
|
-
|
294
|
+
1. For the FIRST mention of a file, use the full relative path
|
295
|
+
2. For SUBSEQUENT mentions of the same file, use ONLY the filename without path
|
296
|
+
- Example: First mention: "utils/helpers/format.js" → Subsequent mentions: "format.js"
|
297
|
+
3. Only include the full path again if there are multiple files with the same name
|
298
|
+
4. For repeated mentions of the same file, consider grouping related changes in one bullet
|
299
|
+
5. Avoid breaking filenames across lines
|
300
|
+
6. Only include function names when they add clarity
|
333
301
|
|
334
302
|
COMMIT TYPES:
|
335
303
|
- feat: New user-facing features
|
@@ -351,6 +319,46 @@ COMMIT TYPES:
|
|
351
319
|
- ui: User interface changes
|
352
320
|
- api: API-related changes
|
353
321
|
|
322
|
+
EXAMPLES:
|
323
|
+
|
324
|
+
1. Bug fix with UI scope:
|
325
|
+
fix(ui): correct primary button focus style
|
326
|
+
|
327
|
+
- [fix] Add :focus outline to Button component (Button.jsx:Button())
|
328
|
+
- [chore] Bump Tailwind config to include ring-offset (tailwind.config.js:1-8)
|
329
|
+
- [refactor] Extract common styles into buttonStyles util (styles/buttons.js:1-15)
|
330
|
+
|
331
|
+
2. Feature with API scope:
|
332
|
+
feat(api): add authentication endpoint for OAuth
|
333
|
+
|
334
|
+
- [feat] Implement OAuth authentication route (auth/routes.js:createOAuthRoute())
|
335
|
+
- [feat] Add token validation middleware (middleware/auth.js:validateToken())
|
336
|
+
- [test] Add integration tests for OAuth flow (tests/auth.test.js:45-87)
|
337
|
+
|
338
|
+
3. Multiple types in one commit:
|
339
|
+
refactor(core): simplify data processing pipeline
|
340
|
+
|
341
|
+
- [refactor] Replace nested loops with map/reduce (utils/process.js:transformData())
|
342
|
+
- [perf] Optimize memory usage in large dataset handling (utils/memory.js:optimize())
|
343
|
+
- [fix] Correct edge case in null value handling (utils/validators.js:checkNull())
|
344
|
+
- [test] Update tests for new pipeline structure (tests/pipeline.test.js)
|
345
|
+
|
346
|
+
4. Multiple changes to the same file:
|
347
|
+
refactor(core): simplify context handling for commit prompts
|
348
|
+
|
349
|
+
- [refactor] Remove process_context function (cli/modes/gitcommsg.py:69-124)
|
350
|
+
- [refactor] Update all functions to accept raw context string (gitcommsg.py:create_system_prompt())
|
351
|
+
- [refactor] Replace context_data usages with context (gitcommsg.py)
|
352
|
+
- [docs] Update library usage doc (docs/usage/library_usage.md:516,531-537)
|
353
|
+
- [chore] Bump project version to 2.15.1 (pyproject.toml:3, uv.lock:137)
|
354
|
+
|
355
|
+
BULLET POINT FORMAT:
|
356
|
+
- Each bullet MUST start with a type in square brackets: [type]
|
357
|
+
- DO NOT use the format "- type: description" (without square brackets)
|
358
|
+
- Instead, ALWAYS use "- [type] description" (with square brackets)
|
359
|
+
- Example: "- [feat] Add new login component" (correct)
|
360
|
+
- Not: "- feat: Add new login component" (incorrect)
|
361
|
+
|
354
362
|
RULES:
|
355
363
|
1. BE 100% FACTUAL - Mention ONLY code explicitly shown in the diff
|
356
364
|
2. NEVER invent or assume changes not directly visible in the code
|
@@ -441,23 +449,30 @@ def handle_api_call(client, prompt, system_prompt=None, logger=None, max_retries
|
|
441
449
|
# Exponential backoff
|
442
450
|
wait_seconds *= 2
|
443
451
|
|
444
|
-
def process_with_chunking(client, diff_content,
|
452
|
+
def process_with_chunking(client, diff_content, context, chunk_size=200, recursive=False, logger=None, max_msg_lines=20, max_recursion_depth=3, analyses_chunk_size=None):
|
445
453
|
"""Process diff with chunking to handle large diffs.
|
446
454
|
|
447
455
|
Args:
|
448
456
|
client: The NGPTClient instance
|
449
457
|
diff_content: The diff content to process
|
450
|
-
|
458
|
+
context: The raw context string
|
451
459
|
chunk_size: Maximum number of lines per chunk
|
452
460
|
recursive: Whether to use recursive chunking
|
453
|
-
max_depth: Maximum recursion depth
|
454
461
|
logger: Optional logger instance
|
462
|
+
max_msg_lines: Maximum number of lines in commit message before condensing
|
463
|
+
max_recursion_depth: Maximum recursion depth for message condensing
|
464
|
+
analyses_chunk_size: Maximum number of lines per chunk for recursive analysis chunking
|
455
465
|
|
456
466
|
Returns:
|
457
467
|
str: Generated commit message
|
458
468
|
"""
|
459
|
-
#
|
460
|
-
|
469
|
+
# If analyses_chunk_size not provided, default to chunk_size
|
470
|
+
if analyses_chunk_size is None:
|
471
|
+
analyses_chunk_size = chunk_size
|
472
|
+
|
473
|
+
# Create different system prompts for different stages
|
474
|
+
technical_system_prompt = create_technical_analysis_system_prompt(context)
|
475
|
+
commit_system_prompt = create_system_prompt(context)
|
461
476
|
|
462
477
|
# Log initial diff content
|
463
478
|
if logger:
|
@@ -488,10 +503,10 @@ def process_with_chunking(client, diff_content, context_data, chunk_size=200, re
|
|
488
503
|
if logger:
|
489
504
|
logger.log_template("DEBUG", "CHUNK", chunk_prompt)
|
490
505
|
|
491
|
-
# Process chunk
|
506
|
+
# Process chunk - use technical system prompt for analysis
|
492
507
|
print(f"{COLORS['yellow']}Analyzing changes...{COLORS['reset']}")
|
493
508
|
try:
|
494
|
-
result = handle_api_call(client, chunk_prompt,
|
509
|
+
result = handle_api_call(client, chunk_prompt, technical_system_prompt, logger)
|
495
510
|
partial_analyses.append(result)
|
496
511
|
print(f"{COLORS['green']}✓ Chunk {i+1} processed{COLORS['reset']}")
|
497
512
|
except Exception as e:
|
@@ -517,11 +532,20 @@ def process_with_chunking(client, diff_content, context_data, chunk_size=200, re
|
|
517
532
|
combined_analyses = "\n\n".join(partial_analyses)
|
518
533
|
combined_line_count = len(combined_analyses.splitlines())
|
519
534
|
|
520
|
-
if recursive and combined_line_count >
|
521
|
-
# Use recursive chunking
|
522
|
-
return
|
535
|
+
if recursive and combined_line_count > analyses_chunk_size:
|
536
|
+
# Use recursive analysis chunking
|
537
|
+
return recursive_chunk_analysis(
|
538
|
+
client,
|
539
|
+
combined_analyses,
|
540
|
+
context,
|
541
|
+
analyses_chunk_size,
|
542
|
+
logger,
|
543
|
+
max_msg_lines,
|
544
|
+
max_recursion_depth
|
545
|
+
)
|
523
546
|
else:
|
524
|
-
#
|
547
|
+
# Combined analysis is under the chunk size limit, generate the commit message
|
548
|
+
print(f"{COLORS['green']}Generating commit message from combined analysis...{COLORS['reset']}")
|
525
549
|
combine_prompt = create_combine_prompt(partial_analyses)
|
526
550
|
|
527
551
|
# Log combine template
|
@@ -529,66 +553,62 @@ def process_with_chunking(client, diff_content, context_data, chunk_size=200, re
|
|
529
553
|
logger.log_template("DEBUG", "COMBINE", combine_prompt)
|
530
554
|
|
531
555
|
try:
|
532
|
-
|
533
|
-
|
556
|
+
# Use commit message system prompt for final generation
|
557
|
+
commit_message = handle_api_call(client, combine_prompt, commit_system_prompt, logger)
|
558
|
+
|
559
|
+
# If the commit message is too long, we need to condense it
|
560
|
+
if len(commit_message.splitlines()) > max_msg_lines:
|
561
|
+
return condense_commit_message(
|
562
|
+
client,
|
563
|
+
commit_message,
|
564
|
+
commit_system_prompt,
|
565
|
+
max_msg_lines,
|
566
|
+
max_recursion_depth,
|
567
|
+
1, # Start at depth 1
|
568
|
+
logger
|
569
|
+
)
|
570
|
+
return commit_message
|
534
571
|
except Exception as e:
|
535
572
|
print(f"{COLORS['red']}Error combining analyses: {str(e)}{COLORS['reset']}")
|
536
573
|
if logger:
|
537
574
|
logger.error(f"Error combining analyses: {str(e)}")
|
538
575
|
return None
|
539
576
|
|
540
|
-
def
|
541
|
-
"""
|
577
|
+
def recursive_chunk_analysis(client, combined_analysis, context, chunk_size, logger=None, max_msg_lines=20, max_recursion_depth=3, current_depth=1):
|
578
|
+
"""Recursively chunk and process large analysis results until they're small enough.
|
542
579
|
|
543
580
|
Args:
|
544
581
|
client: The NGPTClient instance
|
545
582
|
combined_analysis: The combined analysis to process
|
546
|
-
|
547
|
-
|
583
|
+
context: The raw context string
|
584
|
+
chunk_size: Maximum number of lines per chunk
|
548
585
|
logger: Optional logger instance
|
549
|
-
|
586
|
+
max_msg_lines: Maximum number of lines in commit message before condensing
|
587
|
+
max_recursion_depth: Maximum recursion depth for message condensing
|
588
|
+
current_depth: Current recursive analysis depth
|
550
589
|
|
551
590
|
Returns:
|
552
591
|
str: Generated commit message
|
553
592
|
"""
|
554
|
-
|
593
|
+
# Create different system prompts for different stages
|
594
|
+
technical_system_prompt = create_technical_analysis_system_prompt(context)
|
595
|
+
commit_system_prompt = create_system_prompt(context)
|
555
596
|
|
556
|
-
print(f"\n{COLORS['cyan']}Recursive chunking level {current_depth}
|
597
|
+
print(f"\n{COLORS['cyan']}Recursive analysis chunking level {current_depth}...{COLORS['reset']}")
|
557
598
|
|
558
599
|
if logger:
|
559
|
-
logger.info(f"Starting recursive chunking at depth {current_depth}
|
600
|
+
logger.info(f"Starting recursive analysis chunking at depth {current_depth}")
|
560
601
|
logger.debug(f"Combined analysis size: {len(combined_analysis.splitlines())} lines")
|
561
602
|
logger.log_content("DEBUG", f"COMBINED_ANALYSIS_DEPTH_{current_depth}", combined_analysis)
|
562
603
|
|
563
|
-
#
|
564
|
-
|
565
|
-
|
566
|
-
# Log rechunk template
|
567
|
-
if logger:
|
568
|
-
logger.log_template("DEBUG", f"RECHUNK_DEPTH_{current_depth}", rechunk_prompt)
|
569
|
-
|
570
|
-
# Process rechunk
|
571
|
-
try:
|
572
|
-
result = handle_api_call(client, rechunk_prompt, system_prompt, logger)
|
573
|
-
|
574
|
-
# Check if further recursive chunking is needed
|
575
|
-
result_line_count = len(result.splitlines())
|
604
|
+
# If analysis is under chunk size, generate the commit message
|
605
|
+
if len(combined_analysis.splitlines()) <= chunk_size:
|
606
|
+
print(f"{COLORS['green']}Analysis is small enough, generating commit message...{COLORS['reset']}")
|
576
607
|
|
577
|
-
|
578
|
-
|
579
|
-
print(f"{COLORS['yellow']}Result still too large ({result_line_count} lines), continuing recursion...{COLORS['reset']}")
|
580
|
-
if logger:
|
581
|
-
logger.info(f"Result still too large ({result_line_count} lines), depth {current_depth}/{max_depth}")
|
582
|
-
|
583
|
-
return recursive_process(client, result, context_data, max_depth, logger, current_depth + 1)
|
584
|
-
else:
|
585
|
-
# Final processing
|
586
|
-
print(f"{COLORS['green']}Recursion complete, generating final commit message...{COLORS['reset']}")
|
587
|
-
|
588
|
-
# Create final combine prompt
|
589
|
-
final_prompt = f"""Create a CONVENTIONAL COMMIT MESSAGE based on these analyzed git changes:
|
608
|
+
# Create final prompt
|
609
|
+
final_prompt = f"""Create a CONVENTIONAL COMMIT MESSAGE based on these analyzed git changes:
|
590
610
|
|
591
|
-
{
|
611
|
+
{combined_analysis}
|
592
612
|
|
593
613
|
FORMAT:
|
594
614
|
type[(scope)]: <concise summary> (max 50 chars)
|
@@ -597,6 +617,13 @@ type[(scope)]: <concise summary> (max 50 chars)
|
|
597
617
|
- [type] <specific change 2> (filename:function/method/line)
|
598
618
|
- [type] <additional changes...>
|
599
619
|
|
620
|
+
BULLET POINT FORMAT:
|
621
|
+
- Each bullet MUST start with a type in square brackets: [type]
|
622
|
+
- DO NOT use the format "- type: description" (without square brackets)
|
623
|
+
- Instead, ALWAYS use "- [type] description" (with square brackets)
|
624
|
+
- Example: "- [feat] Add new login component" (correct)
|
625
|
+
- Not: "- feat: Add new login component" (incorrect)
|
626
|
+
|
600
627
|
RULES:
|
601
628
|
1. First line must be under 50 characters
|
602
629
|
2. Include a blank line after the first line
|
@@ -604,17 +631,281 @@ RULES:
|
|
604
631
|
4. BE SPECIFIC - mention technical details and function names
|
605
632
|
|
606
633
|
DO NOT include any explanation or commentary outside the commit message format."""
|
634
|
+
|
635
|
+
# Log final template
|
636
|
+
if logger:
|
637
|
+
logger.log_template("DEBUG", f"FINAL_PROMPT_DEPTH_{current_depth}", final_prompt)
|
638
|
+
|
639
|
+
# Generate the commit message - use commit message system prompt
|
640
|
+
commit_message = handle_api_call(client, final_prompt, commit_system_prompt, logger)
|
641
|
+
|
642
|
+
if logger:
|
643
|
+
logger.log_content("DEBUG", f"COMMIT_MESSAGE_DEPTH_{current_depth}", commit_message)
|
644
|
+
|
645
|
+
# If the commit message is too long, we need to condense it
|
646
|
+
if len(commit_message.splitlines()) > max_msg_lines:
|
647
|
+
return condense_commit_message(
|
648
|
+
client,
|
649
|
+
commit_message,
|
650
|
+
commit_system_prompt,
|
651
|
+
max_msg_lines,
|
652
|
+
max_recursion_depth,
|
653
|
+
1, # Start at depth 1
|
654
|
+
logger
|
655
|
+
)
|
656
|
+
return commit_message
|
657
|
+
|
658
|
+
# Analysis is still too large, need to chunk it
|
659
|
+
print(f"{COLORS['yellow']}Analysis still too large ({len(combined_analysis.splitlines())} lines), chunking...{COLORS['reset']}")
|
660
|
+
|
661
|
+
# Split the analysis into chunks
|
662
|
+
analysis_chunks = split_into_chunks(combined_analysis, chunk_size)
|
663
|
+
analysis_chunk_count = len(analysis_chunks)
|
664
|
+
|
665
|
+
if logger:
|
666
|
+
logger.info(f"Split analysis into {analysis_chunk_count} chunks at depth {current_depth}")
|
667
|
+
|
668
|
+
# Process each analysis chunk and get a condensed version
|
669
|
+
condensed_chunks = []
|
670
|
+
for i, analysis_chunk in enumerate(analysis_chunks):
|
671
|
+
print(f"\n{COLORS['cyan']}[Analysis chunk {i+1}/{analysis_chunk_count} at depth {current_depth}]{COLORS['reset']}")
|
672
|
+
|
673
|
+
# Create a target size based on how many chunks we have
|
674
|
+
target_size = min(int(chunk_size / analysis_chunk_count), 100) # Make sure it's not too small
|
675
|
+
|
676
|
+
# Create a prompt to condense this analysis chunk
|
677
|
+
condense_prompt = f"""You are analyzing a PORTION of already analyzed git changes. This is analysis data, not raw git diff.
|
678
|
+
|
679
|
+
Take this SECTION of technical analysis and condense it to be UNDER {target_size} lines while preserving the most important technical details.
|
680
|
+
|
681
|
+
Keep the format consistent with the system prompt.
|
682
|
+
Preserve full file paths, function names, and technical changes.
|
683
|
+
Group related changes when appropriate.
|
684
|
+
|
685
|
+
SECTION OF ANALYSIS TO CONDENSE:
|
686
|
+
|
687
|
+
{analysis_chunk}"""
|
688
|
+
|
689
|
+
if logger:
|
690
|
+
logger.log_template("DEBUG", f"CONDENSE_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condense_prompt)
|
691
|
+
|
692
|
+
print(f"{COLORS['yellow']}Condensing analysis chunk {i+1}/{analysis_chunk_count}...{COLORS['reset']}")
|
693
|
+
|
694
|
+
# Condense this analysis chunk - use technical system prompt for condensing analysis
|
695
|
+
try:
|
696
|
+
condensed_chunk = handle_api_call(client, condense_prompt, technical_system_prompt, logger)
|
697
|
+
condensed_chunks.append(condensed_chunk)
|
698
|
+
|
699
|
+
if logger:
|
700
|
+
logger.log_content("DEBUG", f"CONDENSED_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condensed_chunk)
|
701
|
+
|
702
|
+
print(f"{COLORS['green']}✓ Analysis chunk {i+1}/{analysis_chunk_count} condensed{COLORS['reset']}")
|
703
|
+
except Exception as e:
|
704
|
+
print(f"{COLORS['red']}Error condensing analysis chunk {i+1}: {str(e)}{COLORS['reset']}")
|
705
|
+
if logger:
|
706
|
+
logger.error(f"Error condensing analysis chunk {i+1} at depth {current_depth}: {str(e)}")
|
707
|
+
return None
|
708
|
+
|
709
|
+
# Rate limit protection between chunks
|
710
|
+
if i < analysis_chunk_count - 1:
|
711
|
+
print(f"{COLORS['yellow']}Waiting to avoid rate limits...{COLORS['reset']}")
|
712
|
+
time.sleep(5)
|
713
|
+
|
714
|
+
# Combine condensed chunks
|
715
|
+
combined_condensed = "\n\n".join(condensed_chunks)
|
716
|
+
condensed_line_count = len(combined_condensed.splitlines())
|
717
|
+
|
718
|
+
print(f"\n{COLORS['cyan']}Condensed analysis to {condensed_line_count} lines at depth {current_depth}{COLORS['reset']}")
|
719
|
+
|
720
|
+
if logger:
|
721
|
+
logger.info(f"Combined condensed analysis: {condensed_line_count} lines at depth {current_depth}")
|
722
|
+
logger.log_content("DEBUG", f"COMBINED_CONDENSED_DEPTH_{current_depth}", combined_condensed)
|
723
|
+
|
724
|
+
# Recursively process the combined condensed analysis
|
725
|
+
return recursive_chunk_analysis(
|
726
|
+
client,
|
727
|
+
combined_condensed,
|
728
|
+
context,
|
729
|
+
chunk_size,
|
730
|
+
logger,
|
731
|
+
max_msg_lines,
|
732
|
+
max_recursion_depth,
|
733
|
+
current_depth + 1
|
734
|
+
)
|
735
|
+
|
736
|
+
def condense_commit_message(client, commit_message, system_prompt, max_msg_lines, max_recursion_depth, current_depth=1, logger=None):
|
737
|
+
"""Recursively condense a commit message to be under the maximum length.
|
738
|
+
|
739
|
+
Args:
|
740
|
+
client: The NGPTClient instance
|
741
|
+
commit_message: The commit message to condense
|
742
|
+
system_prompt: The system prompt
|
743
|
+
max_msg_lines: Maximum number of lines in commit message
|
744
|
+
max_recursion_depth: Maximum recursion depth for condensing
|
745
|
+
current_depth: Current recursion depth
|
746
|
+
logger: Optional logger instance
|
747
|
+
|
748
|
+
Returns:
|
749
|
+
str: Condensed commit message
|
750
|
+
"""
|
751
|
+
# Always use commit message system prompt for condensing commit messages
|
752
|
+
if not isinstance(system_prompt, str) or not system_prompt.startswith("You are an expert Git commit message writer"):
|
753
|
+
system_prompt = create_system_prompt(None) # Use default commit message system prompt
|
754
|
+
|
755
|
+
commit_lines = len(commit_message.splitlines())
|
756
|
+
print(f"\n{COLORS['cyan']}Commit message has {commit_lines} lines (depth {current_depth}/{max_recursion_depth}){COLORS['reset']}")
|
757
|
+
|
758
|
+
if logger:
|
759
|
+
logger.info(f"Commit message has {commit_lines} lines at depth {current_depth}/{max_recursion_depth}")
|
760
|
+
logger.log_content("DEBUG", f"COMMIT_MESSAGE_DEPTH_{current_depth}", commit_message)
|
761
|
+
|
762
|
+
# If already under the limit, return as is
|
763
|
+
if commit_lines <= max_msg_lines:
|
764
|
+
return commit_message
|
765
|
+
|
766
|
+
# Check if we've reached the maximum recursion depth
|
767
|
+
is_final_depth = current_depth >= max_recursion_depth
|
768
|
+
|
769
|
+
# Create the condense prompt - only mention the specific max_msg_lines at final depth
|
770
|
+
if is_final_depth:
|
771
|
+
condense_prompt = f"""Rewrite this git commit message to be MUST BE AT MOST {max_msg_lines} LINES TOTAL.
|
772
|
+
PRESERVE the first line exactly as is, and keep the most important changes in the bullet points.
|
773
|
+
Group related changes when possible.
|
774
|
+
|
775
|
+
CURRENT MESSAGE (TOO LONG):
|
776
|
+
{commit_message}
|
777
|
+
|
778
|
+
BULLET POINT FORMAT:
|
779
|
+
- Each bullet MUST start with a type in square brackets: [type]
|
780
|
+
- DO NOT use the format "- type: description" (without square brackets)
|
781
|
+
- Instead, ALWAYS use "- [type] description" (with square brackets)
|
782
|
+
- Example: "- [feat] Add new login component" (correct)
|
783
|
+
- Not: "- feat: Add new login component" (incorrect)
|
784
|
+
|
785
|
+
REQUIREMENTS:
|
786
|
+
1. First line must be preserved exactly as is
|
787
|
+
2. MUST BE AT MOST {max_msg_lines} LINES TOTAL including blank lines - THIS IS A HARD REQUIREMENT
|
788
|
+
3. Include the most significant changes
|
789
|
+
4. Group related changes when possible
|
790
|
+
5. Keep proper formatting with bullet points
|
791
|
+
6. Maintain detailed file/function references in each bullet point
|
792
|
+
7. KEEP TYPE TAGS IN SQUARE BRACKETS: [type]"""
|
793
|
+
else:
|
794
|
+
# At earlier depths, don't specify the exact line count limit
|
795
|
+
condense_prompt = f"""Rewrite this git commit message to be more concise.
|
796
|
+
PRESERVE the first line exactly as is, and keep the most important changes in the bullet points.
|
797
|
+
Group related changes when possible.
|
798
|
+
|
799
|
+
CURRENT MESSAGE (TOO LONG):
|
800
|
+
{commit_message}
|
801
|
+
|
802
|
+
BULLET POINT FORMAT:
|
803
|
+
- Each bullet MUST start with a type in square brackets: [type]
|
804
|
+
- DO NOT use the format "- type: description" (without square brackets)
|
805
|
+
- Instead, ALWAYS use "- [type] description" (with square brackets)
|
806
|
+
- Example: "- [feat] Add new login component" (correct)
|
807
|
+
- Not: "- feat: Add new login component" (incorrect)
|
808
|
+
|
809
|
+
REQUIREMENTS:
|
810
|
+
1. First line must be preserved exactly as is
|
811
|
+
2. Make the message significantly shorter while preserving key information
|
812
|
+
3. Include the most significant changes
|
813
|
+
4. Group related changes when possible
|
814
|
+
5. Keep proper formatting with bullet points
|
815
|
+
6. Maintain detailed file/function references in each bullet point
|
816
|
+
7. KEEP TYPE TAGS IN SQUARE BRACKETS: [type]"""
|
817
|
+
|
818
|
+
if logger:
|
819
|
+
logger.log_template("DEBUG", f"CONDENSE_PROMPT_DEPTH_{current_depth}", condense_prompt)
|
820
|
+
|
821
|
+
print(f"{COLORS['yellow']}Condensing commit message (depth {current_depth}/{max_recursion_depth})...{COLORS['reset']}")
|
822
|
+
|
823
|
+
try:
|
824
|
+
condensed_result = handle_api_call(client, condense_prompt, system_prompt, logger)
|
825
|
+
|
826
|
+
if logger:
|
827
|
+
logger.log_content("DEBUG", f"CONDENSED_RESULT_DEPTH_{current_depth}", condensed_result)
|
828
|
+
|
829
|
+
# Check if we need to condense further
|
830
|
+
condensed_lines = len(condensed_result.splitlines())
|
831
|
+
|
832
|
+
if condensed_lines > max_msg_lines and current_depth < max_recursion_depth:
|
833
|
+
print(f"{COLORS['yellow']}Commit message still has {condensed_lines} lines. Further condensing...{COLORS['reset']}")
|
607
834
|
|
608
|
-
# Log final template
|
609
835
|
if logger:
|
610
|
-
logger.
|
836
|
+
logger.info(f"Commit message still has {condensed_lines} lines after condensing at depth {current_depth}")
|
611
837
|
|
612
|
-
|
838
|
+
# Try again at the next depth
|
839
|
+
return condense_commit_message(
|
840
|
+
client,
|
841
|
+
condensed_result,
|
842
|
+
system_prompt,
|
843
|
+
max_msg_lines,
|
844
|
+
max_recursion_depth,
|
845
|
+
current_depth + 1,
|
846
|
+
logger
|
847
|
+
)
|
848
|
+
else:
|
849
|
+
return condensed_result
|
613
850
|
except Exception as e:
|
614
|
-
print(f"{COLORS['red']}Error
|
851
|
+
print(f"{COLORS['red']}Error condensing commit message: {str(e)}{COLORS['reset']}")
|
615
852
|
if logger:
|
616
|
-
logger.error(f"Error
|
617
|
-
|
853
|
+
logger.error(f"Error condensing commit message at depth {current_depth}: {str(e)}")
|
854
|
+
# Return the original message if condensing fails
|
855
|
+
return commit_message
|
856
|
+
|
857
|
+
def create_combine_prompt(partial_analyses):
|
858
|
+
"""Create prompt for combining partial analyses.
|
859
|
+
|
860
|
+
Args:
|
861
|
+
partial_analyses: List of partial analyses to combine
|
862
|
+
|
863
|
+
Returns:
|
864
|
+
str: Prompt for the AI
|
865
|
+
"""
|
866
|
+
all_analyses = "\n\n".join(partial_analyses)
|
867
|
+
|
868
|
+
return f"""===CRITICAL INSTRUCTION===
|
869
|
+
You are working with ANALYZED SUMMARIES of git changes, NOT raw git diff.
|
870
|
+
The raw git diff has ALREADY been processed into these summaries.
|
871
|
+
|
872
|
+
TASK: Synthesize these partial analyses into a complete conventional commit message
|
873
|
+
following the format specified in the system prompt.
|
874
|
+
|
875
|
+
The analyses to combine:
|
876
|
+
|
877
|
+
{all_analyses}
|
878
|
+
|
879
|
+
RULES FOR FILENAMES:
|
880
|
+
1. For the FIRST mention of a file, use the full relative path
|
881
|
+
2. For SUBSEQUENT mentions of the same file, use ONLY the filename without path
|
882
|
+
- Example: First mention: "utils/helpers/format.js" → Subsequent mentions: "format.js"
|
883
|
+
3. Only include the full path again if there are multiple files with the same name
|
884
|
+
4. For repeated mentions of the same file, consider grouping related changes in one bullet
|
885
|
+
|
886
|
+
BULLET POINT FORMAT:
|
887
|
+
- Each bullet MUST start with a type in square brackets: [type]
|
888
|
+
- DO NOT use the format "- type: description" (without square brackets)
|
889
|
+
- Instead, ALWAYS use "- [type] description" (with square brackets)
|
890
|
+
- Example: "- [feat] Add new login component" (correct)
|
891
|
+
- Not: "- feat: Add new login component" (incorrect)
|
892
|
+
|
893
|
+
EXAMPLE OF PROPERLY FORMATTED COMMIT MESSAGE:
|
894
|
+
refactor(core): simplify context handling for commit prompts
|
895
|
+
|
896
|
+
- [refactor] Remove process_context function (cli/modes/gitcommsg.py:69-124)
|
897
|
+
- [refactor] Update all functions to accept raw context string (gitcommsg.py:create_system_prompt())
|
898
|
+
- [refactor] Replace context_data usages with context (gitcommsg.py)
|
899
|
+
- [docs] Update library usage doc (docs/usage/library_usage.md:516,531-537)
|
900
|
+
- [chore] Bump project version to 2.15.1 (pyproject.toml:3, uv.lock:137)
|
901
|
+
|
902
|
+
REMINDER:
|
903
|
+
- First line must be under 50 characters
|
904
|
+
- Include a blank line after the first line
|
905
|
+
- Each bullet must include specific file references with format [type]
|
906
|
+
- Include specific technical details in each bullet point
|
907
|
+
|
908
|
+
DO NOT ask for the original diff or add explanations outside the commit message format."""
|
618
909
|
|
619
910
|
def gitcommsg_mode(client, args, logger=None):
|
620
911
|
"""Handle the Git commit message generation mode.
|
@@ -678,19 +969,21 @@ def gitcommsg_mode(client, args, logger=None):
|
|
678
969
|
active_logger.log_diff("DEBUG", diff_content)
|
679
970
|
|
680
971
|
# Process context if provided
|
681
|
-
|
972
|
+
context = None
|
682
973
|
if args.message_context:
|
683
|
-
|
974
|
+
context = args.message_context
|
684
975
|
if active_logger:
|
685
|
-
active_logger.debug(f"
|
686
|
-
active_logger.log_content("DEBUG", "
|
976
|
+
active_logger.debug(f"Using raw context: {context}")
|
977
|
+
active_logger.log_content("DEBUG", "CONTEXT", context)
|
687
978
|
|
688
|
-
# Create system
|
689
|
-
|
979
|
+
# Create system prompts for different stages
|
980
|
+
technical_system_prompt = create_technical_analysis_system_prompt(context)
|
981
|
+
commit_system_prompt = create_system_prompt(context)
|
690
982
|
|
691
|
-
# Log system
|
983
|
+
# Log system prompts
|
692
984
|
if active_logger:
|
693
|
-
active_logger.log_template("DEBUG", "
|
985
|
+
active_logger.log_template("DEBUG", "TECHNICAL_SYSTEM", technical_system_prompt)
|
986
|
+
active_logger.log_template("DEBUG", "COMMIT_SYSTEM", commit_system_prompt)
|
694
987
|
|
695
988
|
print(f"\n{COLORS['green']}Generating commit message...{COLORS['reset']}")
|
696
989
|
|
@@ -701,19 +994,36 @@ def gitcommsg_mode(client, args, logger=None):
|
|
701
994
|
if active_logger:
|
702
995
|
active_logger.info(f"Using chunk size: {chunk_size}")
|
703
996
|
|
997
|
+
# Get max_msg_lines from args or use default
|
998
|
+
max_msg_lines = getattr(args, 'max_msg_lines', 20) # Default to 20 if not specified
|
999
|
+
if active_logger:
|
1000
|
+
active_logger.info(f"Maximum commit message lines: {max_msg_lines}")
|
1001
|
+
|
1002
|
+
# Get max_recursion_depth from args or use default
|
1003
|
+
max_recursion_depth = getattr(args, 'max_recursion_depth', 3) # Default to 3 if not specified
|
1004
|
+
if active_logger:
|
1005
|
+
active_logger.info(f"Maximum recursion depth for message condensing: {max_recursion_depth}")
|
1006
|
+
|
1007
|
+
# Get analyses_chunk_size from args or use default
|
1008
|
+
analyses_chunk_size = getattr(args, 'analyses_chunk_size', args.chunk_size) # Default to chunk_size if not specified
|
1009
|
+
if active_logger:
|
1010
|
+
active_logger.info(f"Analyses chunk size: {analyses_chunk_size}")
|
1011
|
+
|
704
1012
|
if args.recursive_chunk:
|
705
1013
|
# Use chunking with recursive processing
|
706
1014
|
if active_logger:
|
707
|
-
active_logger.info(f"Using recursive chunking with
|
1015
|
+
active_logger.info(f"Using recursive chunking with max_recursion_depth: {max_recursion_depth}")
|
708
1016
|
|
709
1017
|
result = process_with_chunking(
|
710
1018
|
client,
|
711
1019
|
diff_content,
|
712
|
-
|
1020
|
+
context,
|
713
1021
|
chunk_size=args.chunk_size,
|
714
1022
|
recursive=True,
|
715
|
-
|
716
|
-
|
1023
|
+
logger=active_logger,
|
1024
|
+
max_msg_lines=max_msg_lines,
|
1025
|
+
max_recursion_depth=max_recursion_depth,
|
1026
|
+
analyses_chunk_size=analyses_chunk_size
|
717
1027
|
)
|
718
1028
|
else:
|
719
1029
|
# Direct processing without chunking
|
@@ -726,7 +1036,25 @@ def gitcommsg_mode(client, args, logger=None):
|
|
726
1036
|
if active_logger:
|
727
1037
|
active_logger.log_template("DEBUG", "DIRECT_PROCESSING", prompt)
|
728
1038
|
|
729
|
-
|
1039
|
+
# Use commit message system prompt for direct processing
|
1040
|
+
result = handle_api_call(client, prompt, commit_system_prompt, active_logger)
|
1041
|
+
|
1042
|
+
# Check if the result exceeds max_msg_lines and recursive_chunk is enabled
|
1043
|
+
if result and len(result.splitlines()) > max_msg_lines:
|
1044
|
+
print(f"{COLORS['yellow']}Commit message exceeds {max_msg_lines} lines, condensing...{COLORS['reset']}")
|
1045
|
+
if active_logger:
|
1046
|
+
active_logger.info(f"Commit message exceeds {max_msg_lines} lines, starting condensing process")
|
1047
|
+
|
1048
|
+
# Use our condense_commit_message function with commit message system prompt
|
1049
|
+
result = condense_commit_message(
|
1050
|
+
client,
|
1051
|
+
result,
|
1052
|
+
commit_system_prompt,
|
1053
|
+
max_msg_lines,
|
1054
|
+
max_recursion_depth,
|
1055
|
+
1, # Start at depth 1
|
1056
|
+
active_logger
|
1057
|
+
)
|
730
1058
|
|
731
1059
|
if not result:
|
732
1060
|
print(f"{COLORS['red']}Failed to generate commit message.{COLORS['reset']}")
|
ngpt/utils/cli_config.py
CHANGED
@@ -24,7 +24,9 @@ CLI_CONFIG_OPTIONS = {
|
|
24
24
|
"recursive-chunk": {"type": "bool", "default": False, "context": ["gitcommsg"]},
|
25
25
|
"diff": {"type": "str", "default": None, "context": ["gitcommsg"]},
|
26
26
|
"chunk-size": {"type": "int", "default": 200, "context": ["gitcommsg"]},
|
27
|
-
"
|
27
|
+
"analyses-chunk-size": {"type": "int", "default": 200, "context": ["gitcommsg"]},
|
28
|
+
"max-msg-lines": {"type": "int", "default": 20, "context": ["gitcommsg"]},
|
29
|
+
"max-recursion-depth": {"type": "int", "default": 3, "context": ["gitcommsg"]},
|
28
30
|
}
|
29
31
|
|
30
32
|
def get_cli_config_dir() -> Path:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ngpt
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.15.1
|
4
4
|
Summary: A lightweight Python CLI and library for interacting with OpenAI-compatible APIs, supporting both official and self-hosted LLM endpoints.
|
5
5
|
Project-URL: Homepage, https://github.com/nazdridoy/ngpt
|
6
6
|
Project-URL: Repository, https://github.com/nazdridoy/ngpt
|
@@ -154,6 +154,13 @@ ngpt --log "Tell me about quantum computing"
|
|
154
154
|
|
155
155
|
# Process text from stdin using the {} placeholder
|
156
156
|
cat README.md | ngpt --stdin "Summarize this document: {}"
|
157
|
+
|
158
|
+
# Use different model providers by specifying the provider name
|
159
|
+
ngpt --provider Groq "Explain quantum computing"
|
160
|
+
|
161
|
+
# Compare outputs from different providers
|
162
|
+
ngpt --provider OpenAI "Explain quantum physics" > openai_response.txt
|
163
|
+
ngpt --provider Ollama "Explain quantum physics" > ollama_response.txt
|
157
164
|
```
|
158
165
|
|
159
166
|
For more examples and detailed usage, visit the [CLI Usage Guide](https://nazdridoy.github.io/ngpt/usage/cli_usage.html).
|
@@ -162,7 +169,7 @@ For more examples and detailed usage, visit the [CLI Usage Guide](https://nazdri
|
|
162
169
|
|
163
170
|
- ✅ **Versatile**: Use as a CLI tool, Python library, or CLI framework for building custom tools
|
164
171
|
- 🪶 **Lightweight**: Minimal dependencies with everything you need included
|
165
|
-
- 🔄 **API Flexibility**: Works with OpenAI, Ollama, Groq, and any compatible endpoint
|
172
|
+
- 🔄 **API Flexibility**: Works with OpenAI, Ollama, Groq, Claude, and any compatible endpoint
|
166
173
|
- 💬 **Interactive Chat**: Continuous conversation with memory in modern UI
|
167
174
|
- 📊 **Streaming Responses**: Real-time output for better user experience
|
168
175
|
- 🔍 **Web Search**: Integrated with compatible API endpoints
|
@@ -179,6 +186,8 @@ For more examples and detailed usage, visit the [CLI Usage Guide](https://nazdri
|
|
179
186
|
- 📃 **Conversation Logging**: Save your conversations to text files for later reference
|
180
187
|
- 🧰 **CLI Components**: Reusable components for building custom AI-powered command-line tools
|
181
188
|
- 🔌 **Modular Architecture**: Well-structured codebase with clean separation of concerns
|
189
|
+
- 🔄 **Provider Switching**: Easily switch between different LLM providers with a single parameter
|
190
|
+
- 🚀 **Performance Optimized**: Fast response times and minimal resource usage
|
182
191
|
|
183
192
|
See the [Feature Overview](https://nazdridoy.github.io/ngpt/overview.html) for more details.
|
184
193
|
|
@@ -327,6 +336,16 @@ print(result.stdout)
|
|
327
336
|
# Returns only code without markdown or explanations
|
328
337
|
code = client.generate_code("function that converts Celsius to Fahrenheit")
|
329
338
|
print(code)
|
339
|
+
|
340
|
+
# Compare responses from different providers
|
341
|
+
openai_config = load_config(config_index=0) # OpenAI
|
342
|
+
groq_config = load_config(config_index=1) # Groq
|
343
|
+
|
344
|
+
openai_client = NGPTClient(**openai_config)
|
345
|
+
groq_client = NGPTClient(**groq_config)
|
346
|
+
|
347
|
+
openai_response = openai_client.chat("Explain quantum computing")
|
348
|
+
groq_response = groq_client.chat("Explain quantum computing")
|
330
349
|
```
|
331
350
|
|
332
351
|
For advanced usage patterns and integrations, check out the [Advanced Examples](https://nazdridoy.github.io/ngpt/examples/advanced.html).
|
@@ -392,6 +411,7 @@ You can configure nGPT using the following options:
|
|
392
411
|
| `-t, --text` | Open interactive multiline editor for complex prompts with syntax highlighting |
|
393
412
|
| `--stdin` | Read from stdin and use content with prompt. Use {} in prompt as placeholder for stdin content |
|
394
413
|
| `--rewrite` | Rewrite text to improve quality while preserving original tone and meaning |
|
414
|
+
| `--gitcommsg` | Generate AI-powered git commit messages from staged changes or diff files |
|
395
415
|
|
396
416
|
#### Global Options
|
397
417
|
|
@@ -2,7 +2,7 @@ ngpt/__init__.py,sha256=kpKhViLakwMdHZkuLht2vWcjt0uD_5gR33gvMhfXr6w,664
|
|
2
2
|
ngpt/__main__.py,sha256=j3eFYPOtCCFBOGh7NK5IWEnADnTMMSEB9GLyIDoW724,66
|
3
3
|
ngpt/client.py,sha256=rLgDPmJe8_yi13-XUiHJ45z54rJVrupxWmeb-fQZGF4,15129
|
4
4
|
ngpt/cli/__init__.py,sha256=hebbDSMGiOd43YNnQP67uzr67Ue6rZPwm2czynr5iZY,43
|
5
|
-
ngpt/cli/args.py,sha256=
|
5
|
+
ngpt/cli/args.py,sha256=VJM6ySMnVrXgKaGb7Qb3AQPYxcQCv3FfCI4x8YkAsLQ,11534
|
6
6
|
ngpt/cli/config_manager.py,sha256=NQQcWnjUppAAd0s0p9YAf8EyKS1ex5-0EB4DvKdB4dk,3662
|
7
7
|
ngpt/cli/formatters.py,sha256=HBYGlx_7eoAKyzfy0Vq5L0yn8yVKjngqYBukMmXCcz0,9401
|
8
8
|
ngpt/cli/interactive.py,sha256=DZFbExcXd7RylkpBiZBhiI6N8FBaT0m_lBes0Pvhi48,10894
|
@@ -12,16 +12,16 @@ ngpt/cli/ui.py,sha256=iMinm_QdsmwrEUpb7CBRexyyBqf4sviFI9M3E8D-hhA,5303
|
|
12
12
|
ngpt/cli/modes/__init__.py,sha256=R3aO662RIzWEOvr3moTrEI8Tpg0zDDyMGGh1-OxiRgM,285
|
13
13
|
ngpt/cli/modes/chat.py,sha256=4a5EgM_5A1zCSrLrjgQMDnBwIHd1Rnu5_BjSKSm7p24,4255
|
14
14
|
ngpt/cli/modes/code.py,sha256=RjOAj7BDO5vLUdIPkUfPtyIkI_W6qEHsZvYh-sIdVaM,4293
|
15
|
-
ngpt/cli/modes/gitcommsg.py,sha256=
|
15
|
+
ngpt/cli/modes/gitcommsg.py,sha256=Kx9pWGWB2bMNFhpBPAa4q7VwHmJQwnZ2qoFrWK7t3gs,45080
|
16
16
|
ngpt/cli/modes/rewrite.py,sha256=Zb0PFvWRKXs4xJCF3GEdYc-LSmy6qRszz8-QJuldHc0,8595
|
17
17
|
ngpt/cli/modes/shell.py,sha256=lF9f7w-0bl_FdZl-WJnZuV736BKrWQtrwoKr3ejPXFE,2682
|
18
18
|
ngpt/cli/modes/text.py,sha256=ncYnfLFMdTPuHiOvAaHNiOWhox6GF6S-2fTwMIrAz-g,3140
|
19
19
|
ngpt/utils/__init__.py,sha256=E46suk2-QgYBI0Qrs6WXOajOUOebF3ETAFY7ah8DTWs,942
|
20
|
-
ngpt/utils/cli_config.py,sha256=
|
20
|
+
ngpt/utils/cli_config.py,sha256=tQxR3a2iXyc5TfRBPQHSUXPInO2dv_zTPGn04eWfmoo,11285
|
21
21
|
ngpt/utils/config.py,sha256=WYOk_b1eiYjo6hpV3pfXr2RjqhOnmKqwZwKid1T41I4,10363
|
22
22
|
ngpt/utils/log.py,sha256=f1jg2iFo35PAmsarH8FVL_62plq4VXH0Mu2QiP6RJGw,15934
|
23
|
-
ngpt-2.
|
24
|
-
ngpt-2.
|
25
|
-
ngpt-2.
|
26
|
-
ngpt-2.
|
27
|
-
ngpt-2.
|
23
|
+
ngpt-2.15.1.dist-info/METADATA,sha256=vKoeQ_IrjV2UtPpEGsThb-i8wg6OE46qXw-UDZdj9YQ,23523
|
24
|
+
ngpt-2.15.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
ngpt-2.15.1.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
|
26
|
+
ngpt-2.15.1.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
27
|
+
ngpt-2.15.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|