ngpt 2.14.0__py3-none-any.whl → 2.15.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ngpt/cli/args.py CHANGED
@@ -94,12 +94,16 @@ def setup_argument_parser():
94
94
  help='Context to guide AI generation (e.g., file types, commit type)')
95
95
  gitcommsg_group.add_argument('-r', '--recursive-chunk', action='store_true',
96
96
  help='Process large diffs in chunks with recursive analysis if needed')
97
- gitcommsg_group.add_argument('--diff', metavar='FILE',
98
- help='Use diff from specified file instead of staged changes')
97
+ gitcommsg_group.add_argument('--diff', metavar='FILE', nargs='?', const=True,
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('--max-depth', type=int, default=3,
102
- help='Maximum recursion depth for recursive chunking (default: 3)')
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/main.py CHANGED
@@ -46,7 +46,8 @@ def show_cli_config_help():
46
46
  "code": [],
47
47
  "interactive": [],
48
48
  "text": [],
49
- "shell": []
49
+ "shell": [],
50
+ "gitcommsg": [] # Add gitcommsg context
50
51
  }
51
52
 
52
53
  for option, meta in CLI_CONFIG_OPTIONS.items():
@@ -71,7 +72,8 @@ def show_cli_config_help():
71
72
  ("code", "Code generation mode"),
72
73
  ("interactive", "Interactive mode"),
73
74
  ("text", "Text mode"),
74
- ("shell", "Shell mode")
75
+ ("shell", "Shell mode"),
76
+ ("gitcommsg", "Git commit message mode") # Add gitcommsg mode
75
77
  ]:
76
78
  if context_groups[mode]:
77
79
  print(f"\n {COLORS['yellow']}Options for {options}:{COLORS['reset']}")
@@ -88,6 +90,8 @@ def show_cli_config_help():
88
90
  print(f" {COLORS['yellow']}ngpt --cli-config set language java{COLORS['reset']} - Set default language to java for code generation")
89
91
  print(f" {COLORS['yellow']}ngpt --cli-config set temperature 0.9{COLORS['reset']} - Set default temperature to 0.9")
90
92
  print(f" {COLORS['yellow']}ngpt --cli-config set no-stream true{COLORS['reset']} - Disable streaming by default")
93
+ print(f" {COLORS['yellow']}ngpt --cli-config set recursive-chunk true{COLORS['reset']} - Enable recursive chunking for git commit messages")
94
+ print(f" {COLORS['yellow']}ngpt --cli-config set diff /path/to/file.diff{COLORS['reset']} - Set default diff file for git commit messages")
91
95
  print(f" {COLORS['yellow']}ngpt --cli-config get temperature{COLORS['reset']} - Check the current temperature setting")
92
96
  print(f" {COLORS['yellow']}ngpt --cli-config get{COLORS['reset']} - Show all current CLI settings")
93
97
  print(f" {COLORS['yellow']}ngpt --cli-config unset language{COLORS['reset']} - Remove language setting")
@@ -562,7 +566,7 @@ def main():
562
566
 
563
567
  elif args.gitcommsg:
564
568
  # Apply CLI config for gitcommsg mode
565
- args = apply_cli_config(args, "all")
569
+ args = apply_cli_config(args, "gitcommsg")
566
570
 
567
571
  # Git commit message generation mode
568
572
  gitcommsg_mode(client, args, logger=logger)
@@ -8,6 +8,7 @@ from datetime import datetime
8
8
  import logging
9
9
  from ..formatters import COLORS
10
10
  from ...utils.log import create_gitcommsg_logger
11
+ from ...utils.cli_config import get_cli_config_option
11
12
 
12
13
  def get_diff_content(diff_file=None):
13
14
  """Get git diff content from file or git staged changes.
@@ -112,8 +113,74 @@ def process_context(context):
112
113
 
113
114
  return context_data
114
115
 
116
+ def create_technical_analysis_system_prompt(context_data=None):
117
+ """Create system prompt for technical analysis based on context data.
118
+
119
+ Args:
120
+ context_data: The processed context data
121
+
122
+ Returns:
123
+ str: System prompt for the technical analysis stage
124
+ """
125
+ 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.
126
+
127
+ OUTPUT FORMAT:
128
+ [FILES]: Comma-separated list of affected files with full paths
129
+
130
+ [CHANGES]:
131
+ - Technical detail 1 (include specific function/method names and line numbers)
132
+ - Technical detail 2 (be precise about exactly what code was added/modified/removed)
133
+ - Additional technical details (include ALL significant changes in this chunk)
134
+
135
+ [IMPACT]: Brief technical description of what the changes accomplish
136
+
137
+ RULES:
138
+ 1. BE 100% FACTUAL - Mention ONLY code explicitly shown in the diff
139
+ 2. NEVER invent or assume changes not directly visible in the code
140
+ 3. ALWAYS identify exact function names, method names, class names, and line numbers where possible
141
+ 4. Use format 'filename:function_name()' or 'filename:line_number' when referencing code locations
142
+ 5. Be precise and factual - only describe code that actually changed
143
+ 6. Include ALL significant changes (do not skip any important modifications)
144
+ 7. Focus on technical specifics, avoid general statements
145
+ 8. When analyzing multiple files, clearly separate each file's changes
146
+ 9. Include proper technical details (method names, component identifiers, etc.)"""
147
+
148
+ if not context_data:
149
+ return base_prompt
150
+
151
+ # Add file type filtering instructions
152
+ if context_data.get("file_type_filter"):
153
+ file_type = context_data["file_type_filter"]
154
+ file_type_prompt = f"""
155
+
156
+ CRITICAL FILE TYPE FILTERING:
157
+ You MUST INCLUDE ONLY changes to {file_type} files or files related to {file_type}.
158
+ You MUST EXCLUDE ALL other files completely from your output.
159
+ This is a strict filter - no exceptions allowed."""
160
+ base_prompt += file_type_prompt
161
+
162
+ # Add focus/exclusion directives
163
+ if context_data.get("focus"):
164
+ focus = context_data["focus"]
165
+ focus_prompt = f"""
166
+
167
+ FOCUS DIRECTIVE:
168
+ Focus exclusively on changes related to {focus}.
169
+ Exclude everything else from your analysis."""
170
+ base_prompt += focus_prompt
171
+
172
+ if context_data.get("exclusions"):
173
+ exclusions = ", ".join(context_data["exclusions"])
174
+ exclusion_prompt = f"""
175
+
176
+ EXCLUSION DIRECTIVE:
177
+ Completely ignore and exclude any mentions of: {exclusions}."""
178
+ base_prompt += exclusion_prompt
179
+
180
+ return base_prompt
181
+
115
182
  def create_system_prompt(context_data=None):
116
- """Create system prompt based on context data.
183
+ """Create system prompt for commit message generation based on context data.
117
184
 
118
185
  Args:
119
186
  context_data: The processed context data
@@ -217,21 +284,14 @@ def create_chunk_prompt(chunk):
217
284
  Returns:
218
285
  str: Prompt for the AI
219
286
  """
220
- return f"""Analyze this PARTIAL git diff and create a detailed technical summary with this EXACT format:
287
+ return f"""Analyze this PARTIAL git diff and create a detailed technical summary.
221
288
 
222
- [FILES]: Comma-separated list of affected files with full paths
289
+ The system prompt already contains your output format instructions with [FILES], [CHANGES], and [IMPACT] sections.
223
290
 
224
- [CHANGES]:
225
- - Technical detail 1 (include specific function/method names and line numbers)
226
- - Technical detail 2 (be precise about exactly what code was added/modified/removed)
227
- - Additional technical details (include ALL significant changes in this chunk)
228
-
229
- [IMPACT]: Brief technical description of what the changes accomplish
230
-
231
- CRITICALLY IMPORTANT: Be extremely specific with technical details.
232
- ALWAYS identify exact function names, method names, class names, and line numbers where possible.
233
- Use format 'filename:function_name()' or 'filename:line_number' when referencing code locations.
234
- Be precise and factual - only describe code that actually changed.
291
+ REMINDER:
292
+ - Identify exact function names, method names, class names, and line numbers
293
+ - Use format 'filename:function_name()' or 'filename:line_number' for references
294
+ - Be precise and factual - only describe code that actually changed
235
295
 
236
296
  Diff chunk:
237
297
 
@@ -250,61 +310,15 @@ def create_rechunk_prompt(combined_analysis, depth):
250
310
  return f"""IMPORTANT: You are analyzing SUMMARIES of git changes, not raw git diff.
251
311
 
252
312
  You are in a re-chunking process (depth: {depth}) where the input is already summarized changes.
253
- Create a TERSE summary of these summaries focusing ONLY ON TECHNICAL CHANGES:
254
-
255
- [CHANGES]:
256
- - Technical change 1 (specific file and function)
257
- - Technical change 2 (specific file and function)
258
- - Additional relevant changes
313
+ Create a terse technical summary following the format in the system prompt.
259
314
 
260
315
  DO NOT ask for raw git diff. These summaries are all you need to work with.
261
- Keep your response FACTUAL and SPECIFIC to what's in the summaries.
316
+ Keep your response factual and specific to what's in the summaries.
262
317
 
263
318
  Section to summarize:
264
319
 
265
320
  {combined_analysis}"""
266
321
 
267
- def create_combine_prompt(partial_analyses):
268
- """Create prompt for combining partial analyses.
269
-
270
- Args:
271
- partial_analyses: List of partial analyses to combine
272
-
273
- Returns:
274
- str: Prompt for the AI
275
- """
276
- all_analyses = "\n\n".join(partial_analyses)
277
-
278
- return f"""===CRITICAL INSTRUCTION===
279
- You are working with ANALYZED SUMMARIES of git changes, NOT raw git diff.
280
- The raw git diff has ALREADY been processed into these summaries.
281
- DO NOT ask for or expect to see the original git diff.
282
-
283
- TASK: Synthesize these partial analyses into a complete conventional commit message:
284
-
285
- {all_analyses}
286
-
287
- Create a CONVENTIONAL COMMIT MESSAGE with:
288
- 1. First line: "type[(scope)]: brief summary" (50 chars max)
289
- - Include scope ONLY if you are 100% confident about the affected area
290
- - Omit scope if changes affect multiple areas or scope is unclear
291
- 2. ⚠️ ONE BLANK LINE IS MANDATORY - NEVER SKIP THIS STEP ⚠️
292
- - This blank line MUST be present in EVERY commit message
293
- - The blank line separates the summary from the detailed changes
294
- - Without this blank line, the commit message format is invalid
295
- 3. Bullet points with specific changes, each with appropriate [type] tag
296
- 4. Reference files in EACH bullet point with function names or line numbers
297
-
298
- FILENAME & FUNCTION HANDLING RULES:
299
- - Include SPECIFIC function names, method names, or line numbers when available
300
- - Format as filename:function() or filename:line_number
301
- - Use short relative paths for files
302
- - Group related changes to the same file when appropriate
303
- - Avoid breaking long filenames across lines
304
-
305
- STRICTLY follow this format with NO EXPLANATION or additional commentary.
306
- DO NOT mention insufficient information or ask for the original diff."""
307
-
308
322
  def create_final_prompt(diff_content):
309
323
  """Create prompt for direct processing without chunking.
310
324
 
@@ -350,6 +364,13 @@ COMMIT TYPES:
350
364
  - ui: User interface changes
351
365
  - api: API-related changes
352
366
 
367
+ BULLET POINT FORMAT:
368
+ - Each bullet MUST start with a type in square brackets: [type]
369
+ - DO NOT use the format "- type: description" (without square brackets)
370
+ - Instead, ALWAYS use "- [type] description" (with square brackets)
371
+ - Example: "- [feat] Add new login component" (correct)
372
+ - Not: "- feat: Add new login component" (incorrect)
373
+
353
374
  RULES:
354
375
  1. BE 100% FACTUAL - Mention ONLY code explicitly shown in the diff
355
376
  2. NEVER invent or assume changes not directly visible in the code
@@ -440,7 +461,7 @@ def handle_api_call(client, prompt, system_prompt=None, logger=None, max_retries
440
461
  # Exponential backoff
441
462
  wait_seconds *= 2
442
463
 
443
- def process_with_chunking(client, diff_content, context_data, chunk_size=200, recursive=False, max_depth=3, logger=None):
464
+ def process_with_chunking(client, diff_content, context_data, chunk_size=200, recursive=False, logger=None, max_msg_lines=20, max_recursion_depth=3, analyses_chunk_size=None):
444
465
  """Process diff with chunking to handle large diffs.
445
466
 
446
467
  Args:
@@ -449,14 +470,21 @@ def process_with_chunking(client, diff_content, context_data, chunk_size=200, re
449
470
  context_data: The processed context data
450
471
  chunk_size: Maximum number of lines per chunk
451
472
  recursive: Whether to use recursive chunking
452
- max_depth: Maximum recursion depth
453
473
  logger: Optional logger instance
474
+ max_msg_lines: Maximum number of lines in commit message before condensing
475
+ max_recursion_depth: Maximum recursion depth for message condensing
476
+ analyses_chunk_size: Maximum number of lines per chunk for recursive analysis chunking
454
477
 
455
478
  Returns:
456
479
  str: Generated commit message
457
480
  """
458
- # Create system prompt
459
- system_prompt = create_system_prompt(context_data)
481
+ # If analyses_chunk_size not provided, default to chunk_size
482
+ if analyses_chunk_size is None:
483
+ analyses_chunk_size = chunk_size
484
+
485
+ # Create different system prompts for different stages
486
+ technical_system_prompt = create_technical_analysis_system_prompt(context_data)
487
+ commit_system_prompt = create_system_prompt(context_data)
460
488
 
461
489
  # Log initial diff content
462
490
  if logger:
@@ -487,10 +515,10 @@ def process_with_chunking(client, diff_content, context_data, chunk_size=200, re
487
515
  if logger:
488
516
  logger.log_template("DEBUG", "CHUNK", chunk_prompt)
489
517
 
490
- # Process chunk
518
+ # Process chunk - use technical system prompt for analysis
491
519
  print(f"{COLORS['yellow']}Analyzing changes...{COLORS['reset']}")
492
520
  try:
493
- result = handle_api_call(client, chunk_prompt, system_prompt, logger)
521
+ result = handle_api_call(client, chunk_prompt, technical_system_prompt, logger)
494
522
  partial_analyses.append(result)
495
523
  print(f"{COLORS['green']}✓ Chunk {i+1} processed{COLORS['reset']}")
496
524
  except Exception as e:
@@ -516,11 +544,20 @@ def process_with_chunking(client, diff_content, context_data, chunk_size=200, re
516
544
  combined_analyses = "\n\n".join(partial_analyses)
517
545
  combined_line_count = len(combined_analyses.splitlines())
518
546
 
519
- if recursive and combined_line_count > 50 and max_depth > 0:
520
- # Use recursive chunking
521
- return recursive_process(client, combined_analyses, context_data, max_depth, logger)
547
+ if recursive and combined_line_count > analyses_chunk_size:
548
+ # Use recursive analysis chunking
549
+ return recursive_chunk_analysis(
550
+ client,
551
+ combined_analyses,
552
+ context_data,
553
+ analyses_chunk_size,
554
+ logger,
555
+ max_msg_lines,
556
+ max_recursion_depth
557
+ )
522
558
  else:
523
- # Use direct combination
559
+ # Combined analysis is under the chunk size limit, generate the commit message
560
+ print(f"{COLORS['green']}Generating commit message from combined analysis...{COLORS['reset']}")
524
561
  combine_prompt = create_combine_prompt(partial_analyses)
525
562
 
526
563
  # Log combine template
@@ -528,66 +565,62 @@ def process_with_chunking(client, diff_content, context_data, chunk_size=200, re
528
565
  logger.log_template("DEBUG", "COMBINE", combine_prompt)
529
566
 
530
567
  try:
531
- result = handle_api_call(client, combine_prompt, system_prompt, logger)
532
- return result
568
+ # Use commit message system prompt for final generation
569
+ commit_message = handle_api_call(client, combine_prompt, commit_system_prompt, logger)
570
+
571
+ # If the commit message is too long, we need to condense it
572
+ if len(commit_message.splitlines()) > max_msg_lines:
573
+ return condense_commit_message(
574
+ client,
575
+ commit_message,
576
+ commit_system_prompt,
577
+ max_msg_lines,
578
+ max_recursion_depth,
579
+ 1, # Start at depth 1
580
+ logger
581
+ )
582
+ return commit_message
533
583
  except Exception as e:
534
584
  print(f"{COLORS['red']}Error combining analyses: {str(e)}{COLORS['reset']}")
535
585
  if logger:
536
586
  logger.error(f"Error combining analyses: {str(e)}")
537
587
  return None
538
588
 
539
- def recursive_process(client, combined_analysis, context_data, max_depth, logger=None, current_depth=1):
540
- """Process large analysis results recursively.
589
+ def recursive_chunk_analysis(client, combined_analysis, context_data, chunk_size, logger=None, max_msg_lines=20, max_recursion_depth=3, current_depth=1):
590
+ """Recursively chunk and process large analysis results until they're small enough.
541
591
 
542
592
  Args:
543
593
  client: The NGPTClient instance
544
594
  combined_analysis: The combined analysis to process
545
595
  context_data: The processed context data
546
- max_depth: Maximum recursion depth
596
+ chunk_size: Maximum number of lines per chunk
547
597
  logger: Optional logger instance
548
- current_depth: Current recursion depth
598
+ max_msg_lines: Maximum number of lines in commit message before condensing
599
+ max_recursion_depth: Maximum recursion depth for message condensing
600
+ current_depth: Current recursive analysis depth
549
601
 
550
602
  Returns:
551
603
  str: Generated commit message
552
604
  """
553
- system_prompt = create_system_prompt(context_data)
605
+ # Create different system prompts for different stages
606
+ technical_system_prompt = create_technical_analysis_system_prompt(context_data)
607
+ commit_system_prompt = create_system_prompt(context_data)
554
608
 
555
- print(f"\n{COLORS['cyan']}Recursive chunking level {current_depth}/{max_depth}...{COLORS['reset']}")
609
+ print(f"\n{COLORS['cyan']}Recursive analysis chunking level {current_depth}...{COLORS['reset']}")
556
610
 
557
611
  if logger:
558
- logger.info(f"Starting recursive chunking at depth {current_depth}/{max_depth}")
612
+ logger.info(f"Starting recursive analysis chunking at depth {current_depth}")
559
613
  logger.debug(f"Combined analysis size: {len(combined_analysis.splitlines())} lines")
560
614
  logger.log_content("DEBUG", f"COMBINED_ANALYSIS_DEPTH_{current_depth}", combined_analysis)
561
615
 
562
- # Create rechunk prompt
563
- rechunk_prompt = create_rechunk_prompt(combined_analysis, current_depth)
564
-
565
- # Log rechunk template
566
- if logger:
567
- logger.log_template("DEBUG", f"RECHUNK_DEPTH_{current_depth}", rechunk_prompt)
568
-
569
- # Process rechunk
570
- try:
571
- result = handle_api_call(client, rechunk_prompt, system_prompt, logger)
572
-
573
- # Check if further recursive chunking is needed
574
- result_line_count = len(result.splitlines())
616
+ # If analysis is under chunk size, generate the commit message
617
+ if len(combined_analysis.splitlines()) <= chunk_size:
618
+ print(f"{COLORS['green']}Analysis is small enough, generating commit message...{COLORS['reset']}")
575
619
 
576
- if result_line_count > 50 and current_depth < max_depth:
577
- # Need another level of chunking
578
- print(f"{COLORS['yellow']}Result still too large ({result_line_count} lines), continuing recursion...{COLORS['reset']}")
579
- if logger:
580
- logger.info(f"Result still too large ({result_line_count} lines), depth {current_depth}/{max_depth}")
581
-
582
- return recursive_process(client, result, context_data, max_depth, logger, current_depth + 1)
583
- else:
584
- # Final processing
585
- print(f"{COLORS['green']}Recursion complete, generating final commit message...{COLORS['reset']}")
586
-
587
- # Create final combine prompt
588
- final_prompt = f"""Create a CONVENTIONAL COMMIT MESSAGE based on these analyzed git changes:
620
+ # Create final prompt
621
+ final_prompt = f"""Create a CONVENTIONAL COMMIT MESSAGE based on these analyzed git changes:
589
622
 
590
- {result}
623
+ {combined_analysis}
591
624
 
592
625
  FORMAT:
593
626
  type[(scope)]: <concise summary> (max 50 chars)
@@ -596,6 +629,13 @@ type[(scope)]: <concise summary> (max 50 chars)
596
629
  - [type] <specific change 2> (filename:function/method/line)
597
630
  - [type] <additional changes...>
598
631
 
632
+ BULLET POINT FORMAT:
633
+ - Each bullet MUST start with a type in square brackets: [type]
634
+ - DO NOT use the format "- type: description" (without square brackets)
635
+ - Instead, ALWAYS use "- [type] description" (with square brackets)
636
+ - Example: "- [feat] Add new login component" (correct)
637
+ - Not: "- feat: Add new login component" (incorrect)
638
+
599
639
  RULES:
600
640
  1. First line must be under 50 characters
601
641
  2. Include a blank line after the first line
@@ -603,17 +643,258 @@ RULES:
603
643
  4. BE SPECIFIC - mention technical details and function names
604
644
 
605
645
  DO NOT include any explanation or commentary outside the commit message format."""
646
+
647
+ # Log final template
648
+ if logger:
649
+ logger.log_template("DEBUG", f"FINAL_PROMPT_DEPTH_{current_depth}", final_prompt)
650
+
651
+ # Generate the commit message - use commit message system prompt
652
+ commit_message = handle_api_call(client, final_prompt, commit_system_prompt, logger)
653
+
654
+ if logger:
655
+ logger.log_content("DEBUG", f"COMMIT_MESSAGE_DEPTH_{current_depth}", commit_message)
656
+
657
+ # If the commit message is too long, we need to condense it
658
+ if len(commit_message.splitlines()) > max_msg_lines:
659
+ return condense_commit_message(
660
+ client,
661
+ commit_message,
662
+ commit_system_prompt,
663
+ max_msg_lines,
664
+ max_recursion_depth,
665
+ 1, # Start at depth 1
666
+ logger
667
+ )
668
+ return commit_message
669
+
670
+ # Analysis is still too large, need to chunk it
671
+ print(f"{COLORS['yellow']}Analysis still too large ({len(combined_analysis.splitlines())} lines), chunking...{COLORS['reset']}")
672
+
673
+ # Split the analysis into chunks
674
+ analysis_chunks = split_into_chunks(combined_analysis, chunk_size)
675
+ analysis_chunk_count = len(analysis_chunks)
676
+
677
+ if logger:
678
+ logger.info(f"Split analysis into {analysis_chunk_count} chunks at depth {current_depth}")
679
+
680
+ # Process each analysis chunk and get a condensed version
681
+ condensed_chunks = []
682
+ for i, analysis_chunk in enumerate(analysis_chunks):
683
+ print(f"\n{COLORS['cyan']}[Analysis chunk {i+1}/{analysis_chunk_count} at depth {current_depth}]{COLORS['reset']}")
684
+
685
+ # Create a target size based on how many chunks we have
686
+ target_size = min(int(chunk_size / analysis_chunk_count), 100) # Make sure it's not too small
687
+
688
+ # Create a prompt to condense this analysis chunk
689
+ condense_prompt = f"""You are analyzing a PORTION of already analyzed git changes. This is analysis data, not raw git diff.
690
+
691
+ Take this SECTION of technical analysis and condense it to be UNDER {target_size} lines while preserving the most important technical details.
692
+
693
+ Keep the format consistent with the system prompt.
694
+ Preserve full file paths, function names, and technical changes.
695
+ Group related changes when appropriate.
696
+
697
+ SECTION OF ANALYSIS TO CONDENSE:
698
+
699
+ {analysis_chunk}"""
700
+
701
+ if logger:
702
+ logger.log_template("DEBUG", f"CONDENSE_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condense_prompt)
703
+
704
+ print(f"{COLORS['yellow']}Condensing analysis chunk {i+1}/{analysis_chunk_count}...{COLORS['reset']}")
705
+
706
+ # Condense this analysis chunk - use technical system prompt for condensing analysis
707
+ try:
708
+ condensed_chunk = handle_api_call(client, condense_prompt, technical_system_prompt, logger)
709
+ condensed_chunks.append(condensed_chunk)
710
+
711
+ if logger:
712
+ logger.log_content("DEBUG", f"CONDENSED_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condensed_chunk)
713
+
714
+ print(f"{COLORS['green']}✓ Analysis chunk {i+1}/{analysis_chunk_count} condensed{COLORS['reset']}")
715
+ except Exception as e:
716
+ print(f"{COLORS['red']}Error condensing analysis chunk {i+1}: {str(e)}{COLORS['reset']}")
717
+ if logger:
718
+ logger.error(f"Error condensing analysis chunk {i+1} at depth {current_depth}: {str(e)}")
719
+ return None
720
+
721
+ # Rate limit protection between chunks
722
+ if i < analysis_chunk_count - 1:
723
+ print(f"{COLORS['yellow']}Waiting to avoid rate limits...{COLORS['reset']}")
724
+ time.sleep(5)
725
+
726
+ # Combine condensed chunks
727
+ combined_condensed = "\n\n".join(condensed_chunks)
728
+ condensed_line_count = len(combined_condensed.splitlines())
729
+
730
+ print(f"\n{COLORS['cyan']}Condensed analysis to {condensed_line_count} lines at depth {current_depth}{COLORS['reset']}")
731
+
732
+ if logger:
733
+ logger.info(f"Combined condensed analysis: {condensed_line_count} lines at depth {current_depth}")
734
+ logger.log_content("DEBUG", f"COMBINED_CONDENSED_DEPTH_{current_depth}", combined_condensed)
735
+
736
+ # Recursively process the combined condensed analysis
737
+ return recursive_chunk_analysis(
738
+ client,
739
+ combined_condensed,
740
+ context_data,
741
+ chunk_size,
742
+ logger,
743
+ max_msg_lines,
744
+ max_recursion_depth,
745
+ current_depth + 1
746
+ )
747
+
748
+ def condense_commit_message(client, commit_message, system_prompt, max_msg_lines, max_recursion_depth, current_depth=1, logger=None):
749
+ """Recursively condense a commit message to be under the maximum length.
750
+
751
+ Args:
752
+ client: The NGPTClient instance
753
+ commit_message: The commit message to condense
754
+ system_prompt: The system prompt
755
+ max_msg_lines: Maximum number of lines in commit message
756
+ max_recursion_depth: Maximum recursion depth for condensing
757
+ current_depth: Current recursion depth
758
+ logger: Optional logger instance
759
+
760
+ Returns:
761
+ str: Condensed commit message
762
+ """
763
+ # Always use commit message system prompt for condensing commit messages
764
+ if not isinstance(system_prompt, str) or not system_prompt.startswith("You are an expert Git commit message writer"):
765
+ system_prompt = create_system_prompt(None) # Use default commit message system prompt
766
+
767
+ commit_lines = len(commit_message.splitlines())
768
+ print(f"\n{COLORS['cyan']}Commit message has {commit_lines} lines (depth {current_depth}/{max_recursion_depth}){COLORS['reset']}")
769
+
770
+ if logger:
771
+ logger.info(f"Commit message has {commit_lines} lines at depth {current_depth}/{max_recursion_depth}")
772
+ logger.log_content("DEBUG", f"COMMIT_MESSAGE_DEPTH_{current_depth}", commit_message)
773
+
774
+ # If already under the limit, return as is
775
+ if commit_lines <= max_msg_lines:
776
+ return commit_message
777
+
778
+ # Check if we've reached the maximum recursion depth
779
+ is_final_depth = current_depth >= max_recursion_depth
780
+
781
+ # Create the condense prompt - only mention the specific max_msg_lines at final depth
782
+ if is_final_depth:
783
+ condense_prompt = f"""Rewrite this git commit message to be MUST BE AT MOST {max_msg_lines} LINES TOTAL.
784
+ PRESERVE the first line exactly as is, and keep the most important changes in the bullet points.
785
+ Group related changes when possible.
786
+
787
+ CURRENT MESSAGE (TOO LONG):
788
+ {commit_message}
789
+
790
+ BULLET POINT FORMAT:
791
+ - Each bullet MUST start with a type in square brackets: [type]
792
+ - DO NOT use the format "- type: description" (without square brackets)
793
+ - Instead, ALWAYS use "- [type] description" (with square brackets)
794
+ - Example: "- [feat] Add new login component" (correct)
795
+ - Not: "- feat: Add new login component" (incorrect)
796
+
797
+ REQUIREMENTS:
798
+ 1. First line must be preserved exactly as is
799
+ 2. MUST BE AT MOST {max_msg_lines} LINES TOTAL including blank lines - THIS IS A HARD REQUIREMENT
800
+ 3. Include the most significant changes
801
+ 4. Group related changes when possible
802
+ 5. Keep proper formatting with bullet points
803
+ 6. Maintain detailed file/function references in each bullet point
804
+ 7. KEEP TYPE TAGS IN SQUARE BRACKETS: [type]"""
805
+ else:
806
+ # At earlier depths, don't specify the exact line count limit
807
+ condense_prompt = f"""Rewrite this git commit message to be more concise.
808
+ PRESERVE the first line exactly as is, and keep the most important changes in the bullet points.
809
+ Group related changes when possible.
810
+
811
+ CURRENT MESSAGE (TOO LONG):
812
+ {commit_message}
813
+
814
+ BULLET POINT FORMAT:
815
+ - Each bullet MUST start with a type in square brackets: [type]
816
+ - DO NOT use the format "- type: description" (without square brackets)
817
+ - Instead, ALWAYS use "- [type] description" (with square brackets)
818
+ - Example: "- [feat] Add new login component" (correct)
819
+ - Not: "- feat: Add new login component" (incorrect)
820
+
821
+ REQUIREMENTS:
822
+ 1. First line must be preserved exactly as is
823
+ 2. Make the message significantly shorter while preserving key information
824
+ 3. Include the most significant changes
825
+ 4. Group related changes when possible
826
+ 5. Keep proper formatting with bullet points
827
+ 6. Maintain detailed file/function references in each bullet point
828
+ 7. KEEP TYPE TAGS IN SQUARE BRACKETS: [type]"""
829
+
830
+ if logger:
831
+ logger.log_template("DEBUG", f"CONDENSE_PROMPT_DEPTH_{current_depth}", condense_prompt)
832
+
833
+ print(f"{COLORS['yellow']}Condensing commit message (depth {current_depth}/{max_recursion_depth})...{COLORS['reset']}")
834
+
835
+ try:
836
+ condensed_result = handle_api_call(client, condense_prompt, system_prompt, logger)
837
+
838
+ if logger:
839
+ logger.log_content("DEBUG", f"CONDENSED_RESULT_DEPTH_{current_depth}", condensed_result)
840
+
841
+ # Check if we need to condense further
842
+ condensed_lines = len(condensed_result.splitlines())
843
+
844
+ if condensed_lines > max_msg_lines and current_depth < max_recursion_depth:
845
+ print(f"{COLORS['yellow']}Commit message still has {condensed_lines} lines. Further condensing...{COLORS['reset']}")
606
846
 
607
- # Log final template
608
847
  if logger:
609
- logger.log_template("DEBUG", "FINAL", final_prompt)
848
+ logger.info(f"Commit message still has {condensed_lines} lines after condensing at depth {current_depth}")
610
849
 
611
- return handle_api_call(client, final_prompt, system_prompt, logger)
850
+ # Try again at the next depth
851
+ return condense_commit_message(
852
+ client,
853
+ condensed_result,
854
+ system_prompt,
855
+ max_msg_lines,
856
+ max_recursion_depth,
857
+ current_depth + 1,
858
+ logger
859
+ )
860
+ else:
861
+ return condensed_result
612
862
  except Exception as e:
613
- print(f"{COLORS['red']}Error in recursive processing: {str(e)}{COLORS['reset']}")
863
+ print(f"{COLORS['red']}Error condensing commit message: {str(e)}{COLORS['reset']}")
614
864
  if logger:
615
- logger.error(f"Error in recursive processing at depth {current_depth}: {str(e)}")
616
- return None
865
+ logger.error(f"Error condensing commit message at depth {current_depth}: {str(e)}")
866
+ # Return the original message if condensing fails
867
+ return commit_message
868
+
869
+ def create_combine_prompt(partial_analyses):
870
+ """Create prompt for combining partial analyses.
871
+
872
+ Args:
873
+ partial_analyses: List of partial analyses to combine
874
+
875
+ Returns:
876
+ str: Prompt for the AI
877
+ """
878
+ all_analyses = "\n\n".join(partial_analyses)
879
+
880
+ return f"""===CRITICAL INSTRUCTION===
881
+ You are working with ANALYZED SUMMARIES of git changes, NOT raw git diff.
882
+ The raw git diff has ALREADY been processed into these summaries.
883
+
884
+ TASK: Synthesize these partial analyses into a complete conventional commit message
885
+ following the format specified in the system prompt.
886
+
887
+ The analyses to combine:
888
+
889
+ {all_analyses}
890
+
891
+ REMINDER:
892
+ - First line must be under 50 characters
893
+ - Include a blank line after the first line
894
+ - Each bullet must include specific file references with format [type]
895
+ - Include specific technical details in each bullet point
896
+
897
+ DO NOT ask for the original diff or add explanations outside the commit message format."""
617
898
 
618
899
  def gitcommsg_mode(client, args, logger=None):
619
900
  """Handle the Git commit message generation mode.
@@ -638,8 +919,35 @@ def gitcommsg_mode(client, args, logger=None):
638
919
  active_logger.debug(f"Args: {args}")
639
920
 
640
921
  try:
922
+ # Check if --diff was explicitly passed on the command line
923
+ diff_option_provided = '--diff' in sys.argv
924
+ diff_path_provided = diff_option_provided and args.diff is not None and args.diff is not True
925
+
926
+ # If --diff wasn't explicitly provided on the command line, don't use the config value
927
+ if not diff_option_provided:
928
+ # Even if diff is in CLI config, don't use it unless --diff flag is provided
929
+ diff_file = None
930
+ if active_logger:
931
+ active_logger.info("Not using diff file from CLI config because --diff flag was not provided")
932
+ else:
933
+ # --diff flag was provided on command line
934
+ if args.diff is True:
935
+ # --diff flag was used without a path, use the value from CLI config
936
+ success, config_diff = get_cli_config_option("diff")
937
+ diff_file = config_diff if success and config_diff else None
938
+ if active_logger:
939
+ if diff_file:
940
+ active_logger.info(f"Using diff file from CLI config: {diff_file}")
941
+ else:
942
+ active_logger.info("No diff file found in CLI config")
943
+ else:
944
+ # --diff flag was used with an explicit path
945
+ diff_file = args.diff
946
+ if active_logger:
947
+ active_logger.info(f"Using explicitly provided diff file: {diff_file}")
948
+
641
949
  # Get diff content
642
- diff_content = get_diff_content(args.diff)
950
+ diff_content = get_diff_content(diff_file)
643
951
 
644
952
  if not diff_content:
645
953
  print(f"{COLORS['red']}No diff content available. Exiting.{COLORS['reset']}")
@@ -657,12 +965,14 @@ def gitcommsg_mode(client, args, logger=None):
657
965
  active_logger.debug(f"Processed context: {context_data}")
658
966
  active_logger.log_content("DEBUG", "CONTEXT_DATA", str(context_data))
659
967
 
660
- # Create system prompt
661
- system_prompt = create_system_prompt(context_data)
968
+ # Create system prompts for different stages
969
+ technical_system_prompt = create_technical_analysis_system_prompt(context_data)
970
+ commit_system_prompt = create_system_prompt(context_data)
662
971
 
663
- # Log system prompt
972
+ # Log system prompts
664
973
  if active_logger:
665
- active_logger.log_template("DEBUG", "SYSTEM", system_prompt)
974
+ active_logger.log_template("DEBUG", "TECHNICAL_SYSTEM", technical_system_prompt)
975
+ active_logger.log_template("DEBUG", "COMMIT_SYSTEM", commit_system_prompt)
666
976
 
667
977
  print(f"\n{COLORS['green']}Generating commit message...{COLORS['reset']}")
668
978
 
@@ -673,10 +983,25 @@ def gitcommsg_mode(client, args, logger=None):
673
983
  if active_logger:
674
984
  active_logger.info(f"Using chunk size: {chunk_size}")
675
985
 
986
+ # Get max_msg_lines from args or use default
987
+ max_msg_lines = getattr(args, 'max_msg_lines', 20) # Default to 20 if not specified
988
+ if active_logger:
989
+ active_logger.info(f"Maximum commit message lines: {max_msg_lines}")
990
+
991
+ # Get max_recursion_depth from args or use default
992
+ max_recursion_depth = getattr(args, 'max_recursion_depth', 3) # Default to 3 if not specified
993
+ if active_logger:
994
+ active_logger.info(f"Maximum recursion depth for message condensing: {max_recursion_depth}")
995
+
996
+ # Get analyses_chunk_size from args or use default
997
+ analyses_chunk_size = getattr(args, 'analyses_chunk_size', args.chunk_size) # Default to chunk_size if not specified
998
+ if active_logger:
999
+ active_logger.info(f"Analyses chunk size: {analyses_chunk_size}")
1000
+
676
1001
  if args.recursive_chunk:
677
1002
  # Use chunking with recursive processing
678
1003
  if active_logger:
679
- active_logger.info(f"Using recursive chunking with max_depth: {args.max_depth}")
1004
+ active_logger.info(f"Using recursive chunking with max_recursion_depth: {max_recursion_depth}")
680
1005
 
681
1006
  result = process_with_chunking(
682
1007
  client,
@@ -684,8 +1009,10 @@ def gitcommsg_mode(client, args, logger=None):
684
1009
  context_data,
685
1010
  chunk_size=args.chunk_size,
686
1011
  recursive=True,
687
- max_depth=args.max_depth,
688
- logger=active_logger
1012
+ logger=active_logger,
1013
+ max_msg_lines=max_msg_lines,
1014
+ max_recursion_depth=max_recursion_depth,
1015
+ analyses_chunk_size=analyses_chunk_size
689
1016
  )
690
1017
  else:
691
1018
  # Direct processing without chunking
@@ -698,7 +1025,25 @@ def gitcommsg_mode(client, args, logger=None):
698
1025
  if active_logger:
699
1026
  active_logger.log_template("DEBUG", "DIRECT_PROCESSING", prompt)
700
1027
 
701
- result = handle_api_call(client, prompt, system_prompt, active_logger)
1028
+ # Use commit message system prompt for direct processing
1029
+ result = handle_api_call(client, prompt, commit_system_prompt, active_logger)
1030
+
1031
+ # Check if the result exceeds max_msg_lines and recursive_chunk is enabled
1032
+ if result and len(result.splitlines()) > max_msg_lines:
1033
+ print(f"{COLORS['yellow']}Commit message exceeds {max_msg_lines} lines, condensing...{COLORS['reset']}")
1034
+ if active_logger:
1035
+ active_logger.info(f"Commit message exceeds {max_msg_lines} lines, starting condensing process")
1036
+
1037
+ # Use our condense_commit_message function with commit message system prompt
1038
+ result = condense_commit_message(
1039
+ client,
1040
+ result,
1041
+ commit_system_prompt,
1042
+ max_msg_lines,
1043
+ max_recursion_depth,
1044
+ 1, # Start at depth 1
1045
+ active_logger
1046
+ )
702
1047
 
703
1048
  if not result:
704
1049
  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
- "max-depth": {"type": "int", "default": 3, "context": ["gitcommsg"]},
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.14.0
3
+ Version: 2.15.0
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,26 +2,26 @@ 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=87b35nG7LFWPwewiICQrgilGIdD_uwqpkgo1DN3xOZY,11073
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
9
- ngpt/cli/main.py,sha256=hFX7Nn9NaRwa6uRp09fnPDzfmbkbbWZNczSLCUZPtLU,28488
9
+ ngpt/cli/main.py,sha256=6GO4r9e9su7FFukj9JeVmJt1bJsqPOJBj6xo3iyMZXU,28911
10
10
  ngpt/cli/renderers.py,sha256=gJ3WdVvCGkNxrLEkLCh6gk9HBFMK8y7an6CsEkqt2Z8,10535
11
11
  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=Su7-e2w5_3-ilgjfo_x055HFC7HROwiyT_jkb667gCM,26637
15
+ ngpt/cli/modes/gitcommsg.py,sha256=Fk3H07DKGW41_nySFUDd6XwtTVdpebdA1hyAm21dB1A,42835
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=b7cXTxbRA-tQWgaehP_uRm_L8-677elPUXk290uzsTs,11110
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.14.0.dist-info/METADATA,sha256=kvuDMT94vqncE_r5Nlw75ijljRMOBtdWRZ_p3bDsP8k,22573
24
- ngpt-2.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
- ngpt-2.14.0.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
26
- ngpt-2.14.0.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
27
- ngpt-2.14.0.dist-info/RECORD,,
23
+ ngpt-2.15.0.dist-info/METADATA,sha256=vXlC2PN84791lHaFgEPOmaRMg4j_3V2BRHSATjGlop4,23523
24
+ ngpt-2.15.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
+ ngpt-2.15.0.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
26
+ ngpt-2.15.0.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
27
+ ngpt-2.15.0.dist-info/RECORD,,
File without changes