ngpt 2.3.3__py3-none-any.whl → 2.4.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.py CHANGED
@@ -302,13 +302,20 @@ def show_config_help():
302
302
  print(f" 5. {COLORS['cyan']}Use --config-index to specify which configuration to use or edit:{COLORS['reset']}")
303
303
  print(f" {COLORS['yellow']}ngpt --config-index 1 \"Your prompt\"{COLORS['reset']}")
304
304
 
305
- print(f" 6. {COLORS['cyan']}Use --config without arguments to add a new configuration:{COLORS['reset']}")
305
+ print(f" 6. {COLORS['cyan']}Use --provider to specify which configuration to use by provider name:{COLORS['reset']}")
306
+ print(f" {COLORS['yellow']}ngpt --provider Gemini \"Your prompt\"{COLORS['reset']}")
307
+
308
+ print(f" 7. {COLORS['cyan']}Use --config without arguments to add a new configuration:{COLORS['reset']}")
306
309
  print(f" {COLORS['yellow']}ngpt --config{COLORS['reset']}")
307
- print(f" Or specify an index to edit an existing configuration:")
310
+ print(f" Or specify an index or provider to edit an existing configuration:")
308
311
  print(f" {COLORS['yellow']}ngpt --config --config-index 1{COLORS['reset']}")
309
- print(f" 7. {COLORS['cyan']}Remove a configuration at a specific index:{COLORS['reset']}")
312
+ print(f" {COLORS['yellow']}ngpt --config --provider Gemini{COLORS['reset']}")
313
+
314
+ print(f" 8. {COLORS['cyan']}Remove a configuration by index or provider:{COLORS['reset']}")
310
315
  print(f" {COLORS['yellow']}ngpt --config --remove --config-index 1{COLORS['reset']}")
311
- print(f" 8. {COLORS['cyan']}List available models for the current configuration:{COLORS['reset']}")
316
+ print(f" {COLORS['yellow']}ngpt --config --remove --provider Gemini{COLORS['reset']}")
317
+
318
+ print(f" 9. {COLORS['cyan']}List available models for the current configuration:{COLORS['reset']}")
312
319
  print(f" {COLORS['yellow']}ngpt --list-models{COLORS['reset']}")
313
320
 
314
321
  def check_config(config):
@@ -325,7 +332,7 @@ def check_config(config):
325
332
 
326
333
  return True
327
334
 
328
- def interactive_chat_session(client, web_search=False, no_stream=False, temperature=0.7, top_p=1.0, max_length=None, log_file=None, preprompt=None):
335
+ def interactive_chat_session(client, web_search=False, no_stream=False, temperature=0.7, top_p=1.0, max_tokens=None, log_file=None, preprompt=None):
329
336
  """Run an interactive chat session with conversation history."""
330
337
  # Get terminal width for better formatting
331
338
  try:
@@ -467,6 +474,7 @@ def interactive_chat_session(client, web_search=False, no_stream=False, temperat
467
474
 
468
475
  # Skip empty messages but don't raise an error
469
476
  if not user_input.strip():
477
+ print(f"{COLORS['yellow']}Empty message skipped. Type 'exit' to quit.{COLORS['reset']}")
470
478
  continue
471
479
 
472
480
  # Add user message to conversation
@@ -492,7 +500,7 @@ def interactive_chat_session(client, web_search=False, no_stream=False, temperat
492
500
  web_search=web_search,
493
501
  temperature=temperature,
494
502
  top_p=top_p,
495
- max_tokens=max_length
503
+ max_tokens=max_tokens
496
504
  )
497
505
 
498
506
  # Add AI response to conversation history
@@ -554,6 +562,7 @@ def main():
554
562
  config_group = parser.add_argument_group('Configuration Options')
555
563
  config_group.add_argument('--config', nargs='?', const=True, help='Path to a custom config file or, if no value provided, enter interactive configuration mode to create a new config')
556
564
  config_group.add_argument('--config-index', type=int, default=0, help='Index of the configuration to use or edit (default: 0)')
565
+ config_group.add_argument('--provider', help='Provider name to identify the configuration to use')
557
566
  config_group.add_argument('--remove', action='store_true', help='Remove the configuration at the specified index (requires --config and --config-index)')
558
567
  config_group.add_argument('--show-config', action='store_true', help='Show the current configuration(s) and exit')
559
568
  config_group.add_argument('--all', action='store_true', help='Show details for all configurations (requires --show-config)')
@@ -572,12 +581,12 @@ def main():
572
581
  help='Set temperature (controls randomness, default: 0.7)')
573
582
  global_group.add_argument('--top_p', type=float, default=1.0,
574
583
  help='Set top_p (controls diversity, default: 1.0)')
575
- global_group.add_argument('--max_length', type=int,
584
+ global_group.add_argument('--max_tokens', type=int,
576
585
  help='Set max response length in tokens')
577
586
  global_group.add_argument('--log', metavar='FILE',
578
587
  help='Set filepath to log conversation to (For interactive modes)')
579
588
  global_group.add_argument('--preprompt',
580
- help='Set preprompt')
589
+ help='Set custom system prompt to control AI behavior')
581
590
 
582
591
  # Mode flags (mutually exclusive)
583
592
  mode_group = parser.add_argument_group('Modes (mutually exclusive)')
@@ -599,6 +608,10 @@ def main():
599
608
  # Validate --all usage
600
609
  if args.all and not args.show_config:
601
610
  parser.error("--all can only be used with --show-config")
611
+
612
+ # Check for mutual exclusivity between --config-index and --provider
613
+ if args.config_index != 0 and args.provider:
614
+ parser.error("--config-index and --provider cannot be used together")
602
615
 
603
616
  # Handle interactive configuration mode
604
617
  if args.config is True: # --config was used without a value
@@ -607,20 +620,46 @@ def main():
607
620
  # Handle configuration removal if --remove flag is present
608
621
  if args.remove:
609
622
  # Validate that config_index is explicitly provided
610
- if '--config-index' not in sys.argv:
611
- parser.error("--remove requires explicitly specifying --config-index")
623
+ if '--config-index' not in sys.argv and not args.provider:
624
+ parser.error("--remove requires explicitly specifying --config-index or --provider")
612
625
 
613
626
  # Show config details before asking for confirmation
614
627
  configs = load_configs(str(config_path))
615
628
 
629
+ # Determine the config index to remove
630
+ config_index = args.config_index
631
+ if args.provider:
632
+ # Find config index by provider name
633
+ matching_configs = [i for i, cfg in enumerate(configs) if cfg.get('provider', '').lower() == args.provider.lower()]
634
+ if not matching_configs:
635
+ print(f"Error: No configuration found for provider '{args.provider}'")
636
+ return
637
+ elif len(matching_configs) > 1:
638
+ print(f"Multiple configurations found for provider '{args.provider}':")
639
+ for i, idx in enumerate(matching_configs):
640
+ print(f" [{i}] Index {idx}: {configs[idx].get('model', 'Unknown model')}")
641
+
642
+ try:
643
+ choice = input("Choose a configuration to remove (or press Enter to cancel): ")
644
+ if choice and choice.isdigit() and 0 <= int(choice) < len(matching_configs):
645
+ config_index = matching_configs[int(choice)]
646
+ else:
647
+ print("Configuration removal cancelled.")
648
+ return
649
+ except (ValueError, IndexError, KeyboardInterrupt):
650
+ print("\nConfiguration removal cancelled.")
651
+ return
652
+ else:
653
+ config_index = matching_configs[0]
654
+
616
655
  # Check if index is valid
617
- if args.config_index < 0 or args.config_index >= len(configs):
618
- print(f"Error: Configuration index {args.config_index} is out of range. Valid range: 0-{len(configs)-1}")
656
+ if config_index < 0 or config_index >= len(configs):
657
+ print(f"Error: Configuration index {config_index} is out of range. Valid range: 0-{len(configs)-1}")
619
658
  return
620
659
 
621
660
  # Show the configuration that will be removed
622
- config = configs[args.config_index]
623
- print(f"Configuration to remove (index {args.config_index}):")
661
+ config = configs[config_index]
662
+ print(f"Configuration to remove (index {config_index}):")
624
663
  print(f" Provider: {config.get('provider', 'N/A')}")
625
664
  print(f" Model: {config.get('model', 'N/A')}")
626
665
  print(f" Base URL: {config.get('base_url', 'N/A')}")
@@ -631,7 +670,7 @@ def main():
631
670
  print("\nAre you sure you want to remove this configuration? [y/N] ", end='')
632
671
  response = input().lower()
633
672
  if response in ('y', 'yes'):
634
- remove_config_entry(config_path, args.config_index)
673
+ remove_config_entry(config_path, config_index)
635
674
  else:
636
675
  print("Configuration removal cancelled.")
637
676
  except KeyboardInterrupt:
@@ -643,20 +682,51 @@ def main():
643
682
  # If --config-index was not explicitly specified, create a new entry by passing None
644
683
  # This will cause add_config_entry to create a new entry at the end of the list
645
684
  # Otherwise, edit the existing config at the specified index
646
- config_index = None if args.config_index == 0 and '--config-index' not in sys.argv else args.config_index
685
+ config_index = None
647
686
 
648
- # Load existing configs to determine the new index if creating a new config
649
- configs = load_configs(str(config_path))
650
- if config_index is None:
651
- print(f"Creating new configuration at index {len(configs)}")
652
- else:
687
+ # Determine if we're editing an existing config or creating a new one
688
+ if args.provider:
689
+ # Find config by provider name
690
+ configs = load_configs(str(config_path))
691
+ matching_configs = [i for i, cfg in enumerate(configs) if cfg.get('provider', '').lower() == args.provider.lower()]
692
+
693
+ if not matching_configs:
694
+ print(f"No configuration found for provider '{args.provider}'. Creating a new configuration.")
695
+ elif len(matching_configs) > 1:
696
+ print(f"Multiple configurations found for provider '{args.provider}':")
697
+ for i, idx in enumerate(matching_configs):
698
+ print(f" [{i}] Index {idx}: {configs[idx].get('model', 'Unknown model')}")
699
+
700
+ try:
701
+ choice = input("Choose a configuration to edit (or press Enter for the first one): ")
702
+ if choice and choice.isdigit() and 0 <= int(choice) < len(matching_configs):
703
+ config_index = matching_configs[int(choice)]
704
+ else:
705
+ config_index = matching_configs[0]
706
+ except (ValueError, IndexError, KeyboardInterrupt):
707
+ config_index = matching_configs[0]
708
+ else:
709
+ config_index = matching_configs[0]
710
+
653
711
  print(f"Editing existing configuration at index {config_index}")
712
+ elif args.config_index != 0 or '--config-index' in sys.argv:
713
+ # Check if the index is valid
714
+ configs = load_configs(str(config_path))
715
+ if args.config_index >= 0 and args.config_index < len(configs):
716
+ config_index = args.config_index
717
+ print(f"Editing existing configuration at index {config_index}")
718
+ else:
719
+ print(f"Configuration index {args.config_index} is out of range. Creating a new configuration.")
720
+ else:
721
+ # Creating a new config
722
+ configs = load_configs(str(config_path))
723
+ print(f"Creating new configuration at index {len(configs)}")
654
724
 
655
725
  add_config_entry(config_path, config_index)
656
726
  return
657
727
 
658
- # Load configuration using the specified index (needed for active config display)
659
- active_config = load_config(args.config, args.config_index)
728
+ # Load configuration using the specified index or provider (needed for active config display)
729
+ active_config = load_config(args.config, args.config_index, args.provider)
660
730
 
661
731
  # Command-line arguments override config settings for active config display
662
732
  # This part is kept to ensure the active config display reflects potential overrides,
@@ -675,31 +745,57 @@ def main():
675
745
 
676
746
  print(f"Configuration file: {config_path}")
677
747
  print(f"Total configurations: {len(configs)}")
678
- print(f"Active configuration index: {args.config_index}")
748
+
749
+ # Determine active configuration and display identifier
750
+ active_identifier = f"index {args.config_index}"
751
+ if args.provider:
752
+ active_identifier = f"provider '{args.provider}'"
753
+ print(f"Active configuration: {active_identifier}")
679
754
 
680
755
  if args.all:
681
756
  # Show details for all configurations
682
757
  print("\nAll configuration details:")
683
758
  for i, cfg in enumerate(configs):
684
- active_str = '(Active)' if i == args.config_index else ''
685
- print(f"\n--- Configuration Index {i} {active_str} ---")
759
+ provider = cfg.get('provider', 'N/A')
760
+ active_str = '(Active)' if (
761
+ (args.provider and provider.lower() == args.provider.lower()) or
762
+ (not args.provider and i == args.config_index)
763
+ ) else ''
764
+ print(f"\n--- Configuration Index {i} / Provider: {COLORS['green']}{provider}{COLORS['reset']} {active_str} ---")
686
765
  print(f" API Key: {'[Set]' if cfg.get('api_key') else '[Not Set]'}")
687
766
  print(f" Base URL: {cfg.get('base_url', 'N/A')}")
688
- print(f" Provider: {cfg.get('provider', 'N/A')}")
689
767
  print(f" Model: {cfg.get('model', 'N/A')}")
690
768
  else:
691
769
  # Show active config details and summary list
692
770
  print("\nActive configuration details:")
771
+ print(f" Provider: {COLORS['green']}{active_config.get('provider', 'N/A')}{COLORS['reset']}")
693
772
  print(f" API Key: {'[Set]' if active_config.get('api_key') else '[Not Set]'}")
694
773
  print(f" Base URL: {active_config.get('base_url', 'N/A')}")
695
- print(f" Provider: {active_config.get('provider', 'N/A')}")
696
774
  print(f" Model: {active_config.get('model', 'N/A')}")
697
775
 
698
776
  if len(configs) > 1:
699
777
  print("\nAvailable configurations:")
778
+ # Check for duplicate provider names for warning
779
+ provider_counts = {}
780
+ for cfg in configs:
781
+ provider = cfg.get('provider', 'N/A').lower()
782
+ provider_counts[provider] = provider_counts.get(provider, 0) + 1
783
+
700
784
  for i, cfg in enumerate(configs):
701
- active_marker = "*" if i == args.config_index else " "
702
- print(f"[{i}]{active_marker} {cfg.get('provider', 'N/A')} - {cfg.get('model', 'N/A')} ({'[API Key Set]' if cfg.get('api_key') else '[API Key Not Set]'})")
785
+ provider = cfg.get('provider', 'N/A')
786
+ provider_display = provider
787
+ # Add warning for duplicate providers
788
+ if provider_counts.get(provider.lower(), 0) > 1:
789
+ provider_display = f"{provider} {COLORS['yellow']}(duplicate){COLORS['reset']}"
790
+
791
+ active_marker = "*" if (
792
+ (args.provider and provider.lower() == args.provider.lower()) or
793
+ (not args.provider and i == args.config_index)
794
+ ) else " "
795
+ print(f"[{i}]{active_marker} {COLORS['green']}{provider_display}{COLORS['reset']} - {cfg.get('model', 'N/A')} ({'[API Key Set]' if cfg.get('api_key') else '[API Key Not Set]'})")
796
+
797
+ # Show instruction for using --provider
798
+ print(f"\nTip: Use {COLORS['yellow']}--provider NAME{COLORS['reset']} to select a configuration by provider name.")
703
799
 
704
800
  return
705
801
 
@@ -738,7 +834,7 @@ def main():
738
834
  # Interactive chat mode
739
835
  interactive_chat_session(client, web_search=args.web_search, no_stream=args.no_stream,
740
836
  temperature=args.temperature, top_p=args.top_p,
741
- max_length=args.max_length, log_file=args.log, preprompt=args.preprompt)
837
+ max_tokens=args.max_tokens, log_file=args.log, preprompt=args.preprompt)
742
838
  elif args.shell:
743
839
  if args.prompt is None:
744
840
  try:
@@ -752,7 +848,7 @@ def main():
752
848
 
753
849
  command = client.generate_shell_command(prompt, web_search=args.web_search,
754
850
  temperature=args.temperature, top_p=args.top_p,
755
- max_length=args.max_length)
851
+ max_tokens=args.max_tokens)
756
852
  if not command:
757
853
  return # Error already printed by client
758
854
 
@@ -790,7 +886,7 @@ def main():
790
886
 
791
887
  generated_code = client.generate_code(prompt, args.language, web_search=args.web_search,
792
888
  temperature=args.temperature, top_p=args.top_p,
793
- max_length=args.max_length)
889
+ max_tokens=args.max_tokens)
794
890
  if generated_code:
795
891
  print(f"\nGenerated code:\n{generated_code}")
796
892
 
@@ -913,7 +1009,7 @@ def main():
913
1009
 
914
1010
  response = client.chat(prompt, stream=not args.no_stream, web_search=args.web_search,
915
1011
  temperature=args.temperature, top_p=args.top_p,
916
- max_tokens=args.max_length, messages=messages)
1012
+ max_tokens=args.max_tokens, messages=messages)
917
1013
  if args.no_stream and response:
918
1014
  print(response)
919
1015
 
@@ -939,7 +1035,7 @@ def main():
939
1035
 
940
1036
  response = client.chat(prompt, stream=not args.no_stream, web_search=args.web_search,
941
1037
  temperature=args.temperature, top_p=args.top_p,
942
- max_tokens=args.max_length, messages=messages)
1038
+ max_tokens=args.max_tokens, messages=messages)
943
1039
  if args.no_stream and response:
944
1040
  print(response)
945
1041
 
ngpt/client.py CHANGED
@@ -167,7 +167,7 @@ class NGPTClient:
167
167
  web_search: bool = False,
168
168
  temperature: float = 0.4,
169
169
  top_p: float = 0.95,
170
- max_length: Optional[int] = None
170
+ max_tokens: Optional[int] = None
171
171
  ) -> str:
172
172
  """
173
173
  Generate a shell command based on the prompt.
@@ -177,7 +177,7 @@ class NGPTClient:
177
177
  web_search: Whether to enable web search capability
178
178
  temperature: Controls randomness in the response
179
179
  top_p: Controls diversity via nucleus sampling
180
- max_length: Maximum number of tokens to generate
180
+ max_tokens: Maximum number of tokens to generate
181
181
 
182
182
  Returns:
183
183
  The generated shell command
@@ -228,7 +228,7 @@ Command:"""
228
228
  web_search=web_search,
229
229
  temperature=temperature,
230
230
  top_p=top_p,
231
- max_tokens=max_length
231
+ max_tokens=max_tokens
232
232
  )
233
233
  except Exception as e:
234
234
  print(f"Error generating shell command: {e}")
@@ -241,7 +241,7 @@ Command:"""
241
241
  web_search: bool = False,
242
242
  temperature: float = 0.4,
243
243
  top_p: float = 0.95,
244
- max_length: Optional[int] = None
244
+ max_tokens: Optional[int] = None
245
245
  ) -> str:
246
246
  """
247
247
  Generate code based on the prompt.
@@ -252,7 +252,7 @@ Command:"""
252
252
  web_search: Whether to enable web search capability
253
253
  temperature: Controls randomness in the response
254
254
  top_p: Controls diversity via nucleus sampling
255
- max_length: Maximum number of tokens to generate
255
+ max_tokens: Maximum number of tokens to generate
256
256
 
257
257
  Returns:
258
258
  The generated code
@@ -285,7 +285,7 @@ Code:"""
285
285
  web_search=web_search,
286
286
  temperature=temperature,
287
287
  top_p=top_p,
288
- max_tokens=max_length
288
+ max_tokens=max_tokens
289
289
  )
290
290
  except Exception as e:
291
291
  print(f"Error generating code: {e}")
ngpt/config.py CHANGED
@@ -75,9 +75,29 @@ def add_config_entry(config_path: Path, config_index: Optional[int] = None) -> N
75
75
  if user_input:
76
76
  entry["base_url"] = user_input
77
77
 
78
- user_input = input(f"Provider [{entry['provider']}]: ")
79
- if user_input:
80
- entry["provider"] = user_input
78
+ # For provider, check for uniqueness when creating new config
79
+ provider_unique = False
80
+ original_provider = entry['provider']
81
+ while not provider_unique:
82
+ user_input = input(f"Provider [{entry['provider']}]: ")
83
+ if user_input:
84
+ provider = user_input
85
+ else:
86
+ provider = entry['provider']
87
+
88
+ # When creating new config or changing provider, check uniqueness
89
+ if is_existing_config and provider.lower() == original_provider.lower():
90
+ # No change in provider name, so keep it
91
+ provider_unique = True
92
+ elif is_provider_unique(configs, provider, config_index if is_existing_config else None):
93
+ provider_unique = True
94
+ else:
95
+ print(f"Error: Provider '{provider}' already exists. Please choose a unique provider name.")
96
+ # If it's the existing provider, allow keeping it (for existing configs)
97
+ if is_existing_config and provider.lower() == original_provider.lower():
98
+ provider_unique = True
99
+
100
+ entry["provider"] = provider
81
101
 
82
102
  user_input = input(f"Model [{entry['model']}]: ")
83
103
  if user_input:
@@ -127,13 +147,46 @@ def load_configs(custom_path: Optional[str] = None) -> List[Dict[str, Any]]:
127
147
 
128
148
  return configs
129
149
 
130
- def load_config(custom_path: Optional[str] = None, config_index: int = 0) -> Dict[str, Any]:
150
+ def load_config(custom_path: Optional[str] = None, config_index: int = 0, provider: Optional[str] = None) -> Dict[str, Any]:
131
151
  """
132
- Load a specific configuration by index and apply environment variables.
152
+ Load a specific configuration by index or provider name and apply environment variables.
133
153
  Environment variables take precedence over the config file.
154
+
155
+ Args:
156
+ custom_path: Optional path to a custom config file
157
+ config_index: Index of the configuration to use (default: 0)
158
+ provider: Provider name to identify the configuration
159
+
160
+ Returns:
161
+ The selected configuration with environment variables applied
134
162
  """
135
163
  configs = load_configs(custom_path)
136
164
 
165
+ # If provider is specified, try to find a matching config
166
+ if provider:
167
+ matching_configs = [i for i, cfg in enumerate(configs) if cfg.get('provider', '').lower() == provider.lower()]
168
+
169
+ if not matching_configs:
170
+ print(f"Warning: No configuration found for provider '{provider}'. Using default configuration.")
171
+ config_index = 0
172
+ elif len(matching_configs) > 1:
173
+ print(f"Warning: Multiple configurations found for provider '{provider}'.")
174
+ for i, idx in enumerate(matching_configs):
175
+ print(f" [{i}] Index {idx}: {configs[idx].get('model', 'Unknown model')}")
176
+
177
+ try:
178
+ choice = input("Choose a configuration (or press Enter for the first one): ")
179
+ if choice and choice.isdigit() and 0 <= int(choice) < len(matching_configs):
180
+ config_index = matching_configs[int(choice)]
181
+ else:
182
+ config_index = matching_configs[0]
183
+ print(f"Using first matching configuration (index {config_index}).")
184
+ except (ValueError, IndexError, KeyboardInterrupt):
185
+ config_index = matching_configs[0]
186
+ print(f"Using first matching configuration (index {config_index}).")
187
+ else:
188
+ config_index = matching_configs[0]
189
+
137
190
  # If config_index is out of range, use the first config
138
191
  if config_index < 0 or config_index >= len(configs):
139
192
  if len(configs) > 0:
@@ -157,7 +210,7 @@ def load_config(custom_path: Optional[str] = None, config_index: int = 0) -> Dic
157
210
  if env_var in os.environ and os.environ[env_var]:
158
211
  config[config_key] = os.environ[env_var]
159
212
 
160
- return config
213
+ return config
161
214
 
162
215
  def remove_config_entry(config_path: Path, config_index: int) -> bool:
163
216
  """
@@ -182,4 +235,24 @@ def remove_config_entry(config_path: Path, config_index: int) -> bool:
182
235
  return True
183
236
  except Exception as e:
184
237
  print(f"Error saving configuration: {e}")
185
- return False
238
+ return False
239
+
240
+ def is_provider_unique(configs: List[Dict[str, Any]], provider: str, exclude_index: Optional[int] = None) -> bool:
241
+ """
242
+ Check if a provider name is unique among configurations.
243
+
244
+ Args:
245
+ configs: List of configuration dictionaries
246
+ provider: Provider name to check
247
+ exclude_index: Optional index to exclude from the check (for updating existing config)
248
+
249
+ Returns:
250
+ True if the provider name is unique, False otherwise
251
+ """
252
+ provider = provider.lower()
253
+ for i, cfg in enumerate(configs):
254
+ if i == exclude_index:
255
+ continue
256
+ if cfg.get('provider', '').lower() == provider:
257
+ return False
258
+ return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngpt
3
- Version: 2.3.3
3
+ Version: 2.4.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
@@ -264,11 +264,12 @@ You can configure the client using the following options:
264
264
  | `-n, --no-stream` | Return the whole response without streaming |
265
265
  | `--temperature` | Set temperature (controls randomness, default: 0.7) |
266
266
  | `--top_p` | Set top_p (controls diversity, default: 1.0) |
267
- | `--max_length` | Set maximum response length in tokens |
267
+ | `--max_tokens` | Set maximum response length in tokens |
268
268
  | `--preprompt` | Set custom system prompt to control AI behavior |
269
269
  | `--log` | Set filepath to log conversation to (for interactive modes) |
270
270
  | `--config` | Path to a custom configuration file or, when used without a value, enters interactive configuration mode |
271
271
  | `--config-index` | Index of the configuration to use (default: 0) |
272
+ | `--provider` | Provider name to identify the configuration to use (alternative to --config-index) |
272
273
  | `--remove` | Remove the configuration at the specified index (requires --config and --config-index) |
273
274
  | `--show-config` | Show configuration details and exit |
274
275
  | `--all` | Used with `--show-config` to display all configurations |
@@ -291,8 +292,17 @@ ngpt --config
291
292
  # Edit an existing configuration at index 1
292
293
  ngpt --config --config-index 1
293
294
 
295
+ # Edit an existing configuration by provider name
296
+ ngpt --config --provider Gemini
297
+
294
298
  # Remove a configuration at index 2
295
299
  ngpt --config --remove --config-index 2
300
+
301
+ # Remove a configuration by provider name
302
+ ngpt --config --remove --provider Gemini
303
+
304
+ # Use a specific configuration by provider name
305
+ ngpt --provider OpenAI "Tell me about quantum computing"
296
306
  ```
297
307
 
298
308
  In interactive mode:
@@ -0,0 +1,9 @@
1
+ ngpt/__init__.py,sha256=ehInP9w0MZlS1vZ1g6Cm4YE1ftmgF72CnEddQ3Le9n4,368
2
+ ngpt/cli.py,sha256=iIlsdKGnSUbdnzKRL6Vmk067KXDEtIZmLqRm8ZKH7XE,49101
3
+ ngpt/client.py,sha256=lJfyLONeBU7YqMVJJys6zPay7gcJTq108_rJ4wvOtok,13067
4
+ ngpt/config.py,sha256=WYOk_b1eiYjo6hpV3pfXr2RjqhOnmKqwZwKid1T41I4,10363
5
+ ngpt-2.4.0.dist-info/METADATA,sha256=Zcfa9uWB3PwwGgFz4fIhmu9XfLu_ZzQxIq7HF8CH-ew,13910
6
+ ngpt-2.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ ngpt-2.4.0.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
8
+ ngpt-2.4.0.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
9
+ ngpt-2.4.0.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- ngpt/__init__.py,sha256=ehInP9w0MZlS1vZ1g6Cm4YE1ftmgF72CnEddQ3Le9n4,368
2
- ngpt/cli.py,sha256=9sQqBUxHQaiaI9QZ7F63Wky19iJIfEk5HmboqxQFpR8,43498
3
- ngpt/client.py,sha256=75xmzO7e9wQ7y_LzZCacg3mkZdheewcBxB6moPftqYw,13067
4
- ngpt/config.py,sha256=BF0G3QeiPma8l7EQyc37bR7LWZog7FHJQNe7uj9cr4w,6896
5
- ngpt-2.3.3.dist-info/METADATA,sha256=pVnJjrQlmXNwdzCyohq-uP9al4GptzXc1nhPwI8ph7Y,13535
6
- ngpt-2.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- ngpt-2.3.3.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
8
- ngpt-2.3.3.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
9
- ngpt-2.3.3.dist-info/RECORD,,
File without changes