janito 2.6.1__py3-none-any.whl → 2.8.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.
Files changed (118) hide show
  1. janito/__init__.py +6 -7
  2. janito/__main__.py +4 -5
  3. janito/_version.py +55 -58
  4. janito/agent/setup_agent.py +308 -241
  5. janito/agent/templates/profiles/{system_prompt_template_software developer.txt.j2 → system_prompt_template_Developer_with_Python_Tools.txt.j2} +43 -39
  6. janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +3 -12
  7. janito/cli/__init__.py +9 -10
  8. janito/cli/chat_mode/bindings.py +38 -38
  9. janito/cli/chat_mode/chat_entry.py +21 -23
  10. janito/cli/chat_mode/prompt_style.py +22 -25
  11. janito/cli/chat_mode/script_runner.py +158 -154
  12. janito/cli/chat_mode/session.py +80 -35
  13. janito/cli/chat_mode/session_profile_select.py +61 -52
  14. janito/cli/chat_mode/shell/commands/__init__.py +1 -5
  15. janito/cli/chat_mode/shell/commands/_priv_check.py +1 -0
  16. janito/cli/chat_mode/shell/commands/bang.py +10 -3
  17. janito/cli/chat_mode/shell/commands/conversation_restart.py +24 -7
  18. janito/cli/chat_mode/shell/commands/execute.py +22 -7
  19. janito/cli/chat_mode/shell/commands/help.py +4 -1
  20. janito/cli/chat_mode/shell/commands/model.py +13 -5
  21. janito/cli/chat_mode/shell/commands/privileges.py +21 -0
  22. janito/cli/chat_mode/shell/commands/prompt.py +0 -2
  23. janito/cli/chat_mode/shell/commands/read.py +22 -5
  24. janito/cli/chat_mode/shell/commands/tools.py +15 -4
  25. janito/cli/chat_mode/shell/commands/write.py +22 -5
  26. janito/cli/chat_mode/shell/input_history.py +3 -1
  27. janito/cli/chat_mode/shell/session/manager.py +0 -2
  28. janito/cli/chat_mode/toolbar.py +25 -19
  29. janito/cli/cli_commands/list_models.py +1 -1
  30. janito/cli/cli_commands/list_providers.py +1 -0
  31. janito/cli/cli_commands/list_tools.py +35 -7
  32. janito/cli/cli_commands/model_utils.py +5 -3
  33. janito/cli/cli_commands/show_config.py +12 -0
  34. janito/cli/cli_commands/show_system_prompt.py +23 -9
  35. janito/cli/config.py +0 -13
  36. janito/cli/core/getters.py +2 -0
  37. janito/cli/core/runner.py +25 -8
  38. janito/cli/core/setters.py +13 -76
  39. janito/cli/main_cli.py +9 -25
  40. janito/cli/prompt_core.py +19 -18
  41. janito/cli/prompt_setup.py +6 -3
  42. janito/cli/rich_terminal_reporter.py +19 -5
  43. janito/cli/single_shot_mode/handler.py +104 -95
  44. janito/cli/verbose_output.py +5 -1
  45. janito/config_manager.py +4 -0
  46. janito/drivers/azure_openai/driver.py +27 -30
  47. janito/drivers/driver_registry.py +27 -27
  48. janito/drivers/openai/driver.py +452 -436
  49. janito/formatting_token.py +12 -4
  50. janito/llm/agent.py +15 -6
  51. janito/llm/driver.py +1 -0
  52. janito/provider_registry.py +139 -178
  53. janito/providers/__init__.py +2 -0
  54. janito/providers/anthropic/model_info.py +40 -41
  55. janito/providers/anthropic/provider.py +75 -80
  56. janito/providers/azure_openai/provider.py +9 -4
  57. janito/providers/deepseek/provider.py +5 -4
  58. janito/providers/google/model_info.py +4 -2
  59. janito/providers/google/provider.py +11 -5
  60. janito/providers/groq/__init__.py +1 -0
  61. janito/providers/groq/model_info.py +46 -0
  62. janito/providers/groq/provider.py +76 -0
  63. janito/providers/moonshotai/__init__.py +1 -0
  64. janito/providers/moonshotai/model_info.py +15 -0
  65. janito/providers/moonshotai/provider.py +89 -0
  66. janito/providers/openai/provider.py +6 -7
  67. janito/tools/__init__.py +2 -0
  68. janito/tools/adapters/local/__init__.py +67 -66
  69. janito/tools/adapters/local/adapter.py +21 -4
  70. janito/tools/adapters/local/ask_user.py +1 -0
  71. janito/tools/adapters/local/copy_file.py +1 -0
  72. janito/tools/adapters/local/create_directory.py +1 -0
  73. janito/tools/adapters/local/create_file.py +1 -0
  74. janito/tools/adapters/local/delete_text_in_file.py +2 -1
  75. janito/tools/adapters/local/fetch_url.py +1 -0
  76. janito/tools/adapters/local/find_files.py +7 -6
  77. janito/tools/adapters/local/get_file_outline/core.py +1 -0
  78. janito/tools/adapters/local/get_file_outline/java_outline.py +22 -15
  79. janito/tools/adapters/local/get_file_outline/search_outline.py +1 -0
  80. janito/tools/adapters/local/move_file.py +4 -3
  81. janito/tools/adapters/local/open_html_in_browser.py +15 -5
  82. janito/tools/adapters/local/open_url.py +1 -0
  83. janito/tools/adapters/local/python_code_run.py +1 -0
  84. janito/tools/adapters/local/python_command_run.py +1 -0
  85. janito/tools/adapters/local/python_file_run.py +1 -0
  86. janito/tools/adapters/local/read_files.py +55 -40
  87. janito/tools/adapters/local/remove_directory.py +1 -0
  88. janito/tools/adapters/local/remove_file.py +1 -0
  89. janito/tools/adapters/local/replace_text_in_file.py +4 -3
  90. janito/tools/adapters/local/run_bash_command.py +1 -0
  91. janito/tools/adapters/local/run_powershell_command.py +1 -0
  92. janito/tools/adapters/local/search_text/core.py +18 -17
  93. janito/tools/adapters/local/search_text/match_lines.py +5 -5
  94. janito/tools/adapters/local/search_text/pattern_utils.py +1 -1
  95. janito/tools/adapters/local/search_text/traverse_directory.py +7 -7
  96. janito/tools/adapters/local/validate_file_syntax/core.py +1 -1
  97. janito/tools/adapters/local/validate_file_syntax/html_validator.py +8 -1
  98. janito/tools/disabled_tools.py +68 -0
  99. janito/tools/path_security.py +18 -11
  100. janito/tools/permissions.py +6 -0
  101. janito/tools/permissions_parse.py +4 -3
  102. janito/tools/tool_base.py +11 -5
  103. janito/tools/tool_use_tracker.py +1 -4
  104. janito/tools/tool_utils.py +1 -1
  105. janito/tools/tools_adapter.py +57 -25
  106. {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/METADATA +411 -417
  107. janito-2.8.0.dist-info/RECORD +202 -0
  108. janito/cli/chat_mode/shell/commands/livelogs.py +0 -49
  109. janito/drivers/mistralai/driver.py +0 -41
  110. janito/providers/mistralai/model_info.py +0 -37
  111. janito/providers/mistralai/provider.py +0 -72
  112. janito/providers/provider_static_info.py +0 -18
  113. janito-2.6.1.dist-info/RECORD +0 -199
  114. /janito/agent/templates/profiles/{system_prompt_template_assistant.txt.j2 → system_prompt_template_model_conversation_without_tools_or_context.txt.j2} +0 -0
  115. {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/WHEEL +0 -0
  116. {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/entry_points.txt +0 -0
  117. {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/licenses/LICENSE +0 -0
  118. {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/top_level.txt +0 -0
@@ -25,7 +25,9 @@ def format_tokens(n, tag=None, use_rich=False):
25
25
  return val
26
26
 
27
27
 
28
- def format_token_message_summary(msg_count, usage, width=96, use_rich=False, elapsed=None):
28
+ def format_token_message_summary(
29
+ msg_count, usage, width=96, use_rich=False, elapsed=None
30
+ ):
29
31
  """
30
32
  Returns a string (rich or pt markup) summarizing message count, last token usage, and elapsed time.
31
33
  """
@@ -40,16 +42,22 @@ def format_token_message_summary(msg_count, usage, width=96, use_rich=False, ela
40
42
  f"Completion: {format_tokens(completion_tokens, 'tokens_out', use_rich)}, "
41
43
  f"Total: {format_tokens(total_tokens, 'tokens_total', use_rich)}"
42
44
  )
43
- elapsed_part = f" | Elapsed: [cyan]{elapsed:.2f}s[/cyan]" if elapsed is not None else ""
45
+ elapsed_part = (
46
+ f" | Elapsed: [cyan]{elapsed:.2f}s[/cyan]" if elapsed is not None else ""
47
+ )
44
48
  return f"{left}{tokens_part}{elapsed_part}"
45
49
 
46
50
 
47
- def print_token_message_summary(console, msg_count=None, usage=None, width=96, elapsed=None):
51
+ def print_token_message_summary(
52
+ console, msg_count=None, usage=None, width=96, elapsed=None
53
+ ):
48
54
  """Prints the summary using rich markup, using defaults from perf_singleton if not given. Optionally includes elapsed time."""
49
55
  if usage is None:
50
56
  usage = performance_collector.get_last_request_usage()
51
57
  if msg_count is None:
52
58
  msg_count = performance_collector.get_total_turns() or 0
53
- line = format_token_message_summary(msg_count, usage, width, use_rich=True, elapsed=elapsed)
59
+ line = format_token_message_summary(
60
+ msg_count, usage, width, use_rich=True, elapsed=elapsed
61
+ )
54
62
  if line.strip():
55
63
  console.print(Rule(line))
janito/llm/agent.py CHANGED
@@ -97,6 +97,7 @@ class LLMAgent:
97
97
  # Refresh allowed_permissions in context before rendering
98
98
  from janito.tools.permissions import get_global_allowed_permissions
99
99
  from janito.tools.tool_base import ToolPermissions
100
+
100
101
  perms = get_global_allowed_permissions()
101
102
  if isinstance(perms, ToolPermissions):
102
103
  perm_str = ""
@@ -171,7 +172,7 @@ class LLMAgent:
171
172
  )
172
173
 
173
174
  def _process_next_response(
174
- self, poll_timeout: float = 1.0, max_wait_time: float = 300.0
175
+ self, poll_timeout: float = 1.0, max_wait_time: float = 600.0
175
176
  ):
176
177
  """
177
178
  Wait for a single event from the output queue (with timeout), process it, and return the result.
@@ -213,7 +214,6 @@ class LLMAgent:
213
214
  ]:
214
215
  return (event, False)
215
216
 
216
-
217
217
  def _get_event_from_output_queue(self, poll_timeout):
218
218
  try:
219
219
  return self.output_queue.get(timeout=poll_timeout)
@@ -306,6 +306,7 @@ class LLMAgent:
306
306
  config = self.llm_provider.driver_config
307
307
  loop_count = 1
308
308
  import threading
309
+
309
310
  cancel_event = threading.Event()
310
311
  while True:
311
312
  self._print_verbose_chat_loop(loop_count)
@@ -317,7 +318,9 @@ class LLMAgent:
317
318
  cancel_event.set()
318
319
  raise
319
320
  if getattr(self, "verbose_agent", False):
320
- print(f"[agent] [DEBUG] Returned from _process_next_response: result={result}, added_tool_results={added_tool_results}")
321
+ print(
322
+ f"[agent] [DEBUG] Returned from _process_next_response: result={result}, added_tool_results={added_tool_results}"
323
+ )
321
324
  if self._should_exit_chat_loop(result, added_tool_results):
322
325
  return result
323
326
  loop_count += 1
@@ -332,11 +335,15 @@ class LLMAgent:
332
335
  def _should_exit_chat_loop(self, result, added_tool_results):
333
336
  if result is None:
334
337
  if getattr(self, "verbose_agent", False):
335
- print("[agent] [INFO] Exiting chat loop: _process_next_response returned None result (likely timeout or error). Returning (None, False).")
338
+ print(
339
+ "[agent] [INFO] Exiting chat loop: _process_next_response returned None result (likely timeout or error). Returning (None, False)."
340
+ )
336
341
  return True
337
342
  if not added_tool_results:
338
343
  if getattr(self, "verbose_agent", False):
339
- print(f"[agent] [INFO] Exiting chat loop: _process_next_response returned added_tool_results=False (final response or no more tool calls). Returning result: {result}")
344
+ print(
345
+ f"[agent] [INFO] Exiting chat loop: _process_next_response returned added_tool_results=False (final response or no more tool calls). Returning result: {result}"
346
+ )
340
347
  return True
341
348
  return False
342
349
 
@@ -434,7 +441,9 @@ class LLMAgent:
434
441
  config.model = model_name
435
442
  config.temperature = self._safe_float(getattr(model_spec, "default_temp", None))
436
443
  config.max_tokens = self._safe_int(getattr(model_spec, "max_response", None))
437
- config.max_completion_tokens = self._safe_int(getattr(model_spec, "max_cot", None))
444
+ config.max_completion_tokens = self._safe_int(
445
+ getattr(model_spec, "max_cot", None)
446
+ )
438
447
  config.top_p = None
439
448
  config.presence_penalty = None
440
449
  config.frequency_penalty = None
janito/llm/driver.py CHANGED
@@ -55,6 +55,7 @@ class LLMDriver(ABC):
55
55
  # Validate all tool schemas before starting the thread
56
56
  if self.tools_adapter is not None:
57
57
  from janito.tools.tools_schema import ToolSchemaBase
58
+
58
59
  validator = ToolSchemaBase()
59
60
  for tool in self.tools_adapter.get_tools():
60
61
  # Validate the tool's class (not instance)
@@ -1,178 +1,139 @@
1
- """
2
- ProviderRegistry: Handles provider listing and selection logic for janito CLI.
3
- """
4
-
5
- from rich.table import Table
6
- from janito.cli.console import shared_console
7
- from janito.providers.registry import LLMProviderRegistry
8
- from janito.providers.provider_static_info import STATIC_PROVIDER_METADATA
9
- from janito.llm.auth import LLMAuthManager
10
- import sys
11
- from janito.exceptions import MissingProviderSelectionException
12
-
13
-
14
- class ProviderRegistry:
15
- def list_providers(self):
16
- """List all supported LLM providers as a table using rich, showing if auth is configured and supported model names."""
17
- providers = self._get_provider_names()
18
- table = self._create_table()
19
- rows = self._get_all_provider_rows(providers)
20
- self._add_rows_to_table(table, rows)
21
- self._print_table(table)
22
-
23
- def _get_provider_names(self):
24
- return list(STATIC_PROVIDER_METADATA.keys())
25
-
26
- def _create_table(self):
27
- table = Table(title="Supported LLM Providers")
28
- table.add_column("Provider", style="cyan")
29
- table.add_column("Maintainer", style="yellow", justify="center")
30
- table.add_column("Model Names", style="magenta")
31
- return table
32
-
33
- def _get_all_provider_rows(self, providers):
34
- rows = []
35
- for p in providers:
36
- info = self._get_provider_info(p)
37
- # info is (provider_name, maintainer, model_names, skip)
38
- if len(info) == 4 and info[3]:
39
- continue # skip providers flagged as not implemented
40
- rows.append(info[:3])
41
- rows.sort(key=self._maintainer_sort_key)
42
- return rows
43
-
44
- def _add_rows_to_table(self, table, rows):
45
- for idx, (p, maintainer, model_names) in enumerate(rows):
46
- table.add_row(p, maintainer, model_names)
47
- if idx != len(rows) - 1:
48
- table.add_section()
49
-
50
- def _print_table(self, table):
51
- """Print the table using rich when running in a terminal; otherwise fall back to a plain ASCII listing.
52
- This avoids UnicodeDecodeError when the parent process captures the output with a non-UTF8 encoding.
53
- """
54
- import sys
55
-
56
- if sys.stdout.isatty():
57
- # Safe to use rich's unicode output when attached to an interactive terminal.
58
- shared_console.print(table)
59
- return
60
-
61
- # Fallback: plain ASCII output (render without rich formatting)
62
- print("Supported LLM Providers")
63
- # Build header from column titles
64
- header_titles = [column.header or "" for column in table.columns]
65
- print(" | ".join(header_titles))
66
- # rich.table.Row objects in recent Rich versions don't expose a public `.cells` attribute.
67
- # Instead, cell content is stored in each column's private `_cells` list.
68
- for row_index, _ in enumerate(table.rows):
69
- cells_text = [str(column._cells[row_index]) for column in table.columns]
70
- ascii_row = " | ".join(cells_text).encode("ascii", "ignore").decode("ascii")
71
- print(ascii_row)
72
-
73
- def _get_provider_info(self, provider_name):
74
- static_info = STATIC_PROVIDER_METADATA.get(provider_name, {})
75
- maintainer_val = static_info.get("maintainer", "-")
76
- maintainer = (
77
- "[red]🚨 Needs maintainer[/red]"
78
- if maintainer_val == "Needs maintainer"
79
- else f"👤 {maintainer_val}"
80
- )
81
- model_names = "-"
82
- unavailable_reason = None
83
- skip = False
84
- try:
85
- provider_class = LLMProviderRegistry.get(provider_name)
86
- creds = LLMAuthManager().get_credentials(provider_name)
87
- provider_instance = None
88
- instantiation_failed = False
89
- try:
90
- provider_instance = provider_class()
91
- except NotImplementedError:
92
- skip = True
93
- unavailable_reason = "Not implemented"
94
- model_names = f"[red]❌ Not implemented[/red]"
95
- except Exception as e:
96
- instantiation_failed = True
97
- unavailable_reason = (
98
- f"Unavailable (import error or missing dependency): {str(e)}"
99
- )
100
- model_names = f"[red]❌ {unavailable_reason}[/red]"
101
- if not instantiation_failed and provider_instance is not None:
102
- available, unavailable_reason = self._get_availability(
103
- provider_instance
104
- )
105
- if (
106
- not available
107
- and unavailable_reason
108
- and "not implemented" in str(unavailable_reason).lower()
109
- ):
110
- skip = True
111
- if available:
112
- model_names = self._get_model_names(provider_name)
113
- else:
114
- model_names = f"[red]❌ {unavailable_reason}[/red]"
115
- except Exception as import_error:
116
- model_names = f"[red]❌ Unavailable (cannot import provider module): {str(import_error)}[/red]"
117
- return (provider_name, maintainer, model_names, skip)
118
-
119
- def _get_availability(self, provider_instance):
120
- try:
121
- available = getattr(provider_instance, "available", True)
122
- unavailable_reason = getattr(provider_instance, "unavailable_reason", None)
123
- except Exception as e:
124
- available = False
125
- unavailable_reason = f"Error reading runtime availability: {str(e)}"
126
- return available, unavailable_reason
127
-
128
- def _get_model_names(self, provider_name):
129
- provider_to_specs = {
130
- "openai": "janito.providers.openai.model_info",
131
- "azure_openai": "janito.providers.azure_openai.model_info",
132
- "google": "janito.providers.google.model_info",
133
- "anthropic": "janito.providers.anthropic.model_info",
134
- "deepseek": "janito.providers.deepseek.model_info",
135
- }
136
- if provider_name in provider_to_specs:
137
- try:
138
- mod = __import__(
139
- provider_to_specs[provider_name], fromlist=["MODEL_SPECS"]
140
- )
141
- return ", ".join(mod.MODEL_SPECS.keys())
142
- except Exception:
143
- return "(Error)"
144
- return "-"
145
-
146
- def _maintainer_sort_key(self, row):
147
- maint = row[1]
148
- is_needs_maint = "Needs maintainer" in maint
149
- return (is_needs_maint, row[2] != "✅ Auth")
150
-
151
- def get_provider(self, provider_name):
152
- """Return the provider class for the given provider name. Returns None if not found."""
153
- from janito.providers.registry import LLMProviderRegistry
154
-
155
- if not provider_name:
156
- print("Error: Provider name must be specified.")
157
- return None
158
- provider_class = LLMProviderRegistry.get(provider_name)
159
- if provider_class is None:
160
- available = ', '.join(LLMProviderRegistry.list_providers())
161
- print(f"Error: Provider '{provider_name}' is not recognized. Available providers: {available}.")
162
- return None
163
- return provider_class
164
-
165
- def get_instance(self, provider_name, config=None):
166
- """Return an instance of the provider for the given provider name, optionally passing a config object. Returns None if not found."""
167
- provider_class = self.get_provider(provider_name)
168
- if provider_class is None:
169
- return None
170
- if config is not None:
171
- return provider_class(config=config)
172
- return provider_class()
173
-
174
-
175
- # For backward compatibility
176
- def list_providers():
177
- """Legacy function for listing providers, now uses ProviderRegistry class."""
178
- ProviderRegistry().list_providers()
1
+ """
2
+ ProviderRegistry: Handles provider listing and selection logic for janito CLI.
3
+ """
4
+
5
+ from rich.table import Table
6
+ from janito.cli.console import shared_console
7
+ from janito.providers.registry import LLMProviderRegistry
8
+ from janito.llm.auth import LLMAuthManager
9
+ import sys
10
+ from janito.exceptions import MissingProviderSelectionException
11
+
12
+
13
+ class ProviderRegistry:
14
+ def list_providers(self):
15
+ """List all supported LLM providers as a table using rich, showing if auth is configured and supported model names."""
16
+ providers = self._get_provider_names()
17
+ table = self._create_table()
18
+ rows = self._get_all_provider_rows(providers)
19
+ self._add_rows_to_table(table, rows)
20
+ self._print_table(table)
21
+
22
+ def _get_provider_names(self):
23
+ from janito.providers.registry import LLMProviderRegistry
24
+
25
+ return LLMProviderRegistry.list_providers()
26
+
27
+ def _create_table(self):
28
+ table = Table(title="Supported LLM Providers")
29
+ table.add_column("Provider", style="cyan")
30
+ table.add_column("Maintainer", style="yellow", justify="center")
31
+ table.add_column("Model Names", style="magenta")
32
+ return table
33
+
34
+ def _get_all_provider_rows(self, providers):
35
+ rows = []
36
+ for p in providers:
37
+ info = self._get_provider_info(p)
38
+ # info is (provider_name, maintainer, model_names, skip)
39
+ if len(info) == 4 and info[3]:
40
+ continue # skip providers flagged as not implemented
41
+ rows.append(info[:3])
42
+ rows.sort(key=self._maintainer_sort_key)
43
+ return rows
44
+
45
+ def _add_rows_to_table(self, table, rows):
46
+ for idx, (p, maintainer, model_names) in enumerate(rows):
47
+ table.add_row(p, maintainer, model_names)
48
+ if idx != len(rows) - 1:
49
+ table.add_section()
50
+
51
+ def _print_table(self, table):
52
+ """Print the table using rich when running in a terminal; otherwise fall back to a plain ASCII listing.
53
+ This avoids UnicodeDecodeError when the parent process captures the output with a non-UTF8 encoding.
54
+ """
55
+ import sys
56
+
57
+ if sys.stdout.isatty():
58
+ # Safe to use rich's unicode output when attached to an interactive terminal.
59
+ shared_console.print(table)
60
+ return
61
+
62
+ # Fallback: plain ASCII output (render without rich formatting)
63
+ print("Supported LLM Providers")
64
+ # Build header from column titles
65
+ header_titles = [column.header or "" for column in table.columns]
66
+ print(" | ".join(header_titles))
67
+ # rich.table.Row objects in recent Rich versions don't expose a public `.cells` attribute.
68
+ # Instead, cell content is stored in each column's private `_cells` list.
69
+ for row_index, _ in enumerate(table.rows):
70
+ cells_text = [str(column._cells[row_index]) for column in table.columns]
71
+ ascii_row = " | ".join(cells_text).encode("ascii", "ignore").decode("ascii")
72
+ print(ascii_row)
73
+
74
+ def _get_provider_info(self, provider_name):
75
+ provider_class = LLMProviderRegistry.get(provider_name)
76
+ maintainer = getattr(provider_class, "MAINTAINER", "-")
77
+ maintainer = f"👤 {maintainer}" if maintainer != "-" else maintainer
78
+ model_names = self._get_model_names(provider_name)
79
+ skip = False
80
+ return (provider_name, maintainer, model_names, skip)
81
+
82
+ def _get_model_names(self, provider_name):
83
+ try:
84
+ provider_class = LLMProviderRegistry.get(provider_name)
85
+ module_parts = provider_class.__module__.split(".")
86
+ # Build the correct import path: janito.providers.{provider}.model_info
87
+ model_info_module = f"janito.providers.{provider_name}.model_info"
88
+ model_info_mod = __import__(model_info_module, fromlist=["MODEL_SPECS"])
89
+
90
+ # Handle different model spec variable names
91
+ model_specs = None
92
+ if hasattr(model_info_mod, "MODEL_SPECS"):
93
+ model_specs = model_info_mod.MODEL_SPECS
94
+ elif hasattr(model_info_mod, "MOONSHOTAI_MODEL_SPECS"):
95
+ model_specs = model_info_mod.MOONSHOTAI_MODEL_SPECS
96
+
97
+ if provider_name == "groq":
98
+ return "<any> (must be provided)"
99
+ if model_specs:
100
+ return ", ".join(model_specs.keys())
101
+ return "-"
102
+ except Exception as e:
103
+ return "-"
104
+
105
+ def _maintainer_sort_key(self, row):
106
+ maint = row[1]
107
+ is_needs_maint = "Needs maintainer" in maint
108
+ return (is_needs_maint, row[2] != " Auth")
109
+
110
+ def get_provider(self, provider_name):
111
+ """Return the provider class for the given provider name. Returns None if not found."""
112
+ from janito.providers.registry import LLMProviderRegistry
113
+
114
+ if not provider_name:
115
+ print("Error: Provider name must be specified.")
116
+ return None
117
+ provider_class = LLMProviderRegistry.get(provider_name)
118
+ if provider_class is None:
119
+ available = ", ".join(LLMProviderRegistry.list_providers())
120
+ print(
121
+ f"Error: Provider '{provider_name}' is not recognized. Available providers: {available}."
122
+ )
123
+ return None
124
+ return provider_class
125
+
126
+ def get_instance(self, provider_name, config=None):
127
+ """Return an instance of the provider for the given provider name, optionally passing a config object. Returns None if not found."""
128
+ provider_class = self.get_provider(provider_name)
129
+ if provider_class is None:
130
+ return None
131
+ if config is not None:
132
+ return provider_class(config=config)
133
+ return provider_class()
134
+
135
+
136
+ # For backward compatibility
137
+ def list_providers():
138
+ """Legacy function for listing providers, now uses ProviderRegistry class."""
139
+ ProviderRegistry().list_providers()
@@ -4,3 +4,5 @@ import janito.providers.google.provider
4
4
  import janito.providers.azure_openai.provider
5
5
  import janito.providers.anthropic.provider
6
6
  import janito.providers.deepseek.provider
7
+ import janito.providers.moonshotai.provider
8
+ import janito.providers.groq.provider
@@ -1,41 +1,40 @@
1
- from janito.llm.model import LLMModelInfo
2
-
3
- MODEL_SPECS = {
4
- "claude-opus-4-20250514": LLMModelInfo(
5
- name="claude-opus-4-20250514",
6
- max_response=32000,
7
- default_temp=0.7,
8
- driver="OpenAIModelDriver",
9
- ),
10
- "claude-sonnet-4-20250514": LLMModelInfo(
11
- name="claude-sonnet-4-20250514",
12
- max_response=64000,
13
- default_temp=0.7,
14
- driver="OpenAIModelDriver",
15
- ),
16
- "claude-3-7-sonnet-20250219": LLMModelInfo(
17
- name="claude-3-7-sonnet-20250219",
18
- max_response=64000,
19
- default_temp=0.7,
20
- driver="OpenAIModelDriver",
21
- ),
22
- "claude-3-5-haiku-20241022": LLMModelInfo(
23
- name="claude-3-5-haiku-20241022",
24
- max_response=8192,
25
- default_temp=0.7,
26
- driver="OpenAIModelDriver",
27
- ),
28
- "claude-3-5-sonnet-20241022": LLMModelInfo(
29
- name="claude-3-5-sonnet-20241022",
30
- max_response=8192,
31
- default_temp=0.7,
32
- driver="OpenAIModelDriver",
33
- ),
34
- "claude-3-haiku-20240307": LLMModelInfo(
35
- name="claude-3-haiku-20240307",
36
- max_response=4096,
37
- default_temp=0.7,
38
- driver="OpenAIModelDriver",
39
- ),
40
- }
41
-
1
+ from janito.llm.model import LLMModelInfo
2
+
3
+ MODEL_SPECS = {
4
+ "claude-opus-4-20250514": LLMModelInfo(
5
+ name="claude-opus-4-20250514",
6
+ max_response=32000,
7
+ default_temp=0.7,
8
+ driver="OpenAIModelDriver",
9
+ ),
10
+ "claude-sonnet-4-20250514": LLMModelInfo(
11
+ name="claude-sonnet-4-20250514",
12
+ max_response=64000,
13
+ default_temp=0.7,
14
+ driver="OpenAIModelDriver",
15
+ ),
16
+ "claude-3-7-sonnet-20250219": LLMModelInfo(
17
+ name="claude-3-7-sonnet-20250219",
18
+ max_response=64000,
19
+ default_temp=0.7,
20
+ driver="OpenAIModelDriver",
21
+ ),
22
+ "claude-3-5-haiku-20241022": LLMModelInfo(
23
+ name="claude-3-5-haiku-20241022",
24
+ max_response=8192,
25
+ default_temp=0.7,
26
+ driver="OpenAIModelDriver",
27
+ ),
28
+ "claude-3-5-sonnet-20241022": LLMModelInfo(
29
+ name="claude-3-5-sonnet-20241022",
30
+ max_response=8192,
31
+ default_temp=0.7,
32
+ driver="OpenAIModelDriver",
33
+ ),
34
+ "claude-3-haiku-20240307": LLMModelInfo(
35
+ name="claude-3-haiku-20240307",
36
+ max_response=4096,
37
+ default_temp=0.7,
38
+ driver="OpenAIModelDriver",
39
+ ),
40
+ }