janito 1.14.2__py3-none-any.whl → 2.0.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.
- janito/__init__.py +6 -1
- janito/__main__.py +1 -1
- janito/agent/setup_agent.py +139 -0
- janito/agent/templates/profiles/{system_prompt_template_base.txt.j2 → system_prompt_template_main.txt.j2} +1 -1
- janito/cli/__init__.py +9 -0
- janito/cli/chat_mode/bindings.py +37 -0
- janito/cli/chat_mode/chat_entry.py +23 -0
- janito/cli/chat_mode/prompt_style.py +19 -0
- janito/cli/chat_mode/session.py +272 -0
- janito/{shell/prompt/completer.py → cli/chat_mode/shell/autocomplete.py} +7 -6
- janito/cli/chat_mode/shell/commands/__init__.py +55 -0
- janito/cli/chat_mode/shell/commands/base.py +9 -0
- janito/cli/chat_mode/shell/commands/clear.py +12 -0
- janito/{shell → cli/chat_mode/shell}/commands/conversation_restart.py +34 -30
- janito/cli/chat_mode/shell/commands/edit.py +25 -0
- janito/cli/chat_mode/shell/commands/help.py +16 -0
- janito/cli/chat_mode/shell/commands/history_view.py +93 -0
- janito/cli/chat_mode/shell/commands/lang.py +25 -0
- janito/cli/chat_mode/shell/commands/last.py +137 -0
- janito/cli/chat_mode/shell/commands/livelogs.py +49 -0
- janito/cli/chat_mode/shell/commands/multi.py +51 -0
- janito/cli/chat_mode/shell/commands/prompt.py +64 -0
- janito/cli/chat_mode/shell/commands/role.py +36 -0
- janito/cli/chat_mode/shell/commands/session.py +40 -0
- janito/{shell → cli/chat_mode/shell}/commands/session_control.py +2 -2
- janito/cli/chat_mode/shell/commands/termweb_log.py +92 -0
- janito/cli/chat_mode/shell/commands/tools.py +32 -0
- janito/{shell → cli/chat_mode/shell}/commands/utility.py +4 -7
- janito/{shell → cli/chat_mode/shell}/commands/verbose.py +5 -5
- janito/cli/chat_mode/shell/session/__init__.py +1 -0
- janito/{shell → cli/chat_mode/shell}/session/manager.py +9 -1
- janito/cli/chat_mode/toolbar.py +90 -0
- janito/cli/cli_commands/list_models.py +35 -0
- janito/cli/cli_commands/list_providers.py +9 -0
- janito/cli/cli_commands/list_tools.py +53 -0
- janito/cli/cli_commands/model_selection.py +50 -0
- janito/cli/cli_commands/model_utils.py +84 -0
- janito/cli/cli_commands/set_api_key.py +19 -0
- janito/cli/cli_commands/show_config.py +51 -0
- janito/cli/cli_commands/show_system_prompt.py +62 -0
- janito/cli/config.py +28 -0
- janito/cli/console.py +3 -0
- janito/cli/core/__init__.py +4 -0
- janito/cli/core/event_logger.py +59 -0
- janito/cli/core/getters.py +31 -0
- janito/cli/core/runner.py +141 -0
- janito/cli/core/setters.py +174 -0
- janito/cli/core/unsetters.py +54 -0
- janito/cli/main.py +8 -196
- janito/cli/main_cli.py +312 -0
- janito/cli/prompt_core.py +230 -0
- janito/cli/prompt_handler.py +6 -0
- janito/cli/rich_terminal_reporter.py +101 -0
- janito/cli/single_shot_mode/__init__.py +6 -0
- janito/cli/single_shot_mode/handler.py +137 -0
- janito/cli/termweb_starter.py +73 -24
- janito/cli/utils.py +25 -0
- janito/cli/verbose_output.py +196 -0
- janito/config.py +5 -0
- janito/config_manager.py +110 -0
- janito/conversation_history.py +30 -0
- janito/{agent/tools_utils/dir_walk_utils.py → dir_walk_utils.py} +3 -2
- janito/driver_events.py +98 -0
- janito/drivers/anthropic/driver.py +113 -0
- janito/drivers/azure_openai/driver.py +36 -0
- janito/drivers/driver_registry.py +33 -0
- janito/drivers/google_genai/driver.py +54 -0
- janito/drivers/google_genai/schema_generator.py +67 -0
- janito/drivers/mistralai/driver.py +41 -0
- janito/drivers/openai/driver.py +334 -0
- janito/event_bus/__init__.py +2 -0
- janito/event_bus/bus.py +68 -0
- janito/event_bus/event.py +15 -0
- janito/event_bus/handler.py +31 -0
- janito/event_bus/queue_bus.py +57 -0
- janito/exceptions.py +23 -0
- janito/formatting_token.py +54 -0
- janito/i18n/pt.py +1 -0
- janito/llm/__init__.py +5 -0
- janito/llm/agent.py +443 -0
- janito/llm/auth.py +62 -0
- janito/llm/driver.py +239 -0
- janito/llm/driver_config.py +34 -0
- janito/llm/driver_config_builder.py +34 -0
- janito/llm/driver_input.py +12 -0
- janito/llm/message_parts.py +60 -0
- janito/llm/model.py +38 -0
- janito/llm/provider.py +187 -0
- janito/perf_singleton.py +3 -0
- janito/performance_collector.py +167 -0
- janito/provider_config.py +98 -0
- janito/provider_registry.py +152 -0
- janito/providers/__init__.py +7 -0
- janito/providers/anthropic/model_info.py +22 -0
- janito/providers/anthropic/provider.py +65 -0
- janito/providers/azure_openai/model_info.py +15 -0
- janito/providers/azure_openai/provider.py +72 -0
- janito/providers/deepseek/__init__.py +1 -0
- janito/providers/deepseek/model_info.py +16 -0
- janito/providers/deepseek/provider.py +91 -0
- janito/providers/google/__init__.py +1 -0
- janito/providers/google/model_info.py +40 -0
- janito/providers/google/provider.py +69 -0
- janito/providers/mistralai/model_info.py +37 -0
- janito/providers/mistralai/provider.py +69 -0
- janito/providers/openai/__init__.py +1 -0
- janito/providers/openai/model_info.py +137 -0
- janito/providers/openai/provider.py +107 -0
- janito/providers/openai/schema_generator.py +63 -0
- janito/providers/provider_static_info.py +21 -0
- janito/providers/registry.py +26 -0
- janito/report_events.py +38 -0
- janito/termweb/app.py +1 -1
- janito/tools/__init__.py +16 -0
- janito/tools/adapters/__init__.py +1 -0
- janito/tools/adapters/local/__init__.py +54 -0
- janito/tools/adapters/local/adapter.py +92 -0
- janito/{agent/tools → tools/adapters/local}/ask_user.py +30 -13
- janito/tools/adapters/local/copy_file.py +84 -0
- janito/{agent/tools → tools/adapters/local}/create_directory.py +11 -10
- janito/tools/adapters/local/create_file.py +82 -0
- janito/tools/adapters/local/delete_text_in_file.py +136 -0
- janito/{agent/tools → tools/adapters/local}/fetch_url.py +18 -19
- janito/tools/adapters/local/find_files.py +140 -0
- janito/tools/adapters/local/get_file_outline/core.py +151 -0
- janito/{agent/tools → tools/adapters/local}/get_file_outline/python_outline.py +125 -0
- janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -0
- janito/{agent/tools → tools/adapters/local}/get_file_outline/search_outline.py +12 -7
- janito/{agent/tools → tools/adapters/local}/move_file.py +13 -9
- janito/{agent/tools → tools/adapters/local}/open_url.py +7 -5
- janito/tools/adapters/local/python_code_run.py +165 -0
- janito/tools/adapters/local/python_command_run.py +163 -0
- janito/tools/adapters/local/python_file_run.py +162 -0
- janito/{agent/tools → tools/adapters/local}/remove_directory.py +15 -9
- janito/{agent/tools → tools/adapters/local}/remove_file.py +17 -14
- janito/{agent/tools → tools/adapters/local}/replace_text_in_file.py +27 -22
- janito/tools/adapters/local/run_bash_command.py +176 -0
- janito/tools/adapters/local/run_powershell_command.py +219 -0
- janito/{agent/tools → tools/adapters/local}/search_text/core.py +32 -12
- janito/{agent/tools → tools/adapters/local}/search_text/match_lines.py +13 -4
- janito/{agent/tools → tools/adapters/local}/search_text/pattern_utils.py +12 -4
- janito/{agent/tools → tools/adapters/local}/search_text/traverse_directory.py +15 -2
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/core.py +12 -11
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/css_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/html_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/js_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/json_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/markdown_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/ps1_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/python_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/xml_validator.py +1 -1
- janito/{agent/tools → tools/adapters/local}/validate_file_syntax/yaml_validator.py +1 -1
- janito/{agent/tools/get_lines.py → tools/adapters/local/view_file.py} +45 -27
- janito/tools/inspect_registry.py +17 -0
- janito/tools/tool_base.py +105 -0
- janito/tools/tool_events.py +58 -0
- janito/tools/tool_run_exception.py +12 -0
- janito/{agent → tools}/tool_use_tracker.py +2 -4
- janito/{agent/tools_utils/utils.py → tools/tool_utils.py} +18 -9
- janito/tools/tools_adapter.py +207 -0
- janito/tools/tools_schema.py +104 -0
- janito/utils.py +11 -0
- janito/version.py +4 -0
- janito-2.0.0.dist-info/METADATA +232 -0
- janito-2.0.0.dist-info/RECORD +180 -0
- janito/agent/__init__.py +0 -0
- janito/agent/api_exceptions.py +0 -4
- janito/agent/config.py +0 -147
- janito/agent/config_defaults.py +0 -12
- janito/agent/config_utils.py +0 -0
- janito/agent/content_handler.py +0 -0
- janito/agent/conversation.py +0 -238
- janito/agent/conversation_api.py +0 -306
- janito/agent/conversation_exceptions.py +0 -18
- janito/agent/conversation_tool_calls.py +0 -39
- janito/agent/conversation_ui.py +0 -17
- janito/agent/event.py +0 -24
- janito/agent/event_dispatcher.py +0 -24
- janito/agent/event_handler_protocol.py +0 -5
- janito/agent/event_system.py +0 -15
- janito/agent/llm_conversation_history.py +0 -82
- janito/agent/message_handler.py +0 -20
- janito/agent/message_handler_protocol.py +0 -5
- janito/agent/openai_client.py +0 -149
- janito/agent/openai_schema_generator.py +0 -187
- janito/agent/profile_manager.py +0 -96
- janito/agent/queued_message_handler.py +0 -50
- janito/agent/rich_live.py +0 -32
- janito/agent/rich_message_handler.py +0 -115
- janito/agent/runtime_config.py +0 -36
- janito/agent/test_handler_protocols.py +0 -47
- janito/agent/test_openai_schema_generator.py +0 -93
- janito/agent/tests/__init__.py +0 -1
- janito/agent/tool_base.py +0 -63
- janito/agent/tool_executor.py +0 -122
- janito/agent/tool_registry.py +0 -49
- janito/agent/tools/__init__.py +0 -47
- janito/agent/tools/create_file.py +0 -59
- janito/agent/tools/delete_text_in_file.py +0 -97
- janito/agent/tools/find_files.py +0 -106
- janito/agent/tools/get_file_outline/core.py +0 -81
- janito/agent/tools/present_choices.py +0 -64
- janito/agent/tools/python_command_runner.py +0 -201
- janito/agent/tools/python_file_runner.py +0 -199
- janito/agent/tools/python_stdin_runner.py +0 -208
- janito/agent/tools/replace_file.py +0 -72
- janito/agent/tools/run_bash_command.py +0 -218
- janito/agent/tools/run_powershell_command.py +0 -251
- janito/agent/tools_utils/__init__.py +0 -1
- janito/agent/tools_utils/action_type.py +0 -7
- janito/agent/tools_utils/test_gitignore_utils.py +0 -46
- janito/cli/_livereload_log_utils.py +0 -13
- janito/cli/_print_config.py +0 -96
- janito/cli/_termweb_log_utils.py +0 -17
- janito/cli/_utils.py +0 -9
- janito/cli/arg_parser.py +0 -272
- janito/cli/cli_main.py +0 -281
- janito/cli/config_commands.py +0 -211
- janito/cli/config_runner.py +0 -35
- janito/cli/formatting_runner.py +0 -12
- janito/cli/livereload_starter.py +0 -60
- janito/cli/logging_setup.py +0 -38
- janito/cli/one_shot.py +0 -80
- janito/livereload/app.py +0 -25
- janito/rich_utils.py +0 -59
- janito/shell/__init__.py +0 -0
- janito/shell/commands/__init__.py +0 -61
- janito/shell/commands/config.py +0 -22
- janito/shell/commands/edit.py +0 -24
- janito/shell/commands/history_view.py +0 -18
- janito/shell/commands/lang.py +0 -19
- janito/shell/commands/livelogs.py +0 -42
- janito/shell/commands/prompt.py +0 -62
- janito/shell/commands/termweb_log.py +0 -94
- janito/shell/commands/tools.py +0 -26
- janito/shell/commands/track.py +0 -36
- janito/shell/main.py +0 -326
- janito/shell/prompt/load_prompt.py +0 -57
- janito/shell/prompt/session_setup.py +0 -57
- janito/shell/session/config.py +0 -109
- janito/shell/session/history.py +0 -0
- janito/shell/ui/interactive.py +0 -226
- janito/termweb/static/editor.css +0 -158
- janito/termweb/static/editor.css.bak +0 -145
- janito/termweb/static/editor.html +0 -46
- janito/termweb/static/editor.html.bak +0 -46
- janito/termweb/static/editor.js +0 -265
- janito/termweb/static/editor.js.bak +0 -259
- janito/termweb/static/explorer.html.bak +0 -59
- janito/termweb/static/favicon.ico +0 -0
- janito/termweb/static/favicon.ico.bak +0 -0
- janito/termweb/static/index.html +0 -53
- janito/termweb/static/index.html.bak +0 -54
- janito/termweb/static/index.html.bak.bak +0 -175
- janito/termweb/static/landing.html.bak +0 -36
- janito/termweb/static/termicon.svg +0 -1
- janito/termweb/static/termweb.css +0 -214
- janito/termweb/static/termweb.css.bak +0 -237
- janito/termweb/static/termweb.js +0 -162
- janito/termweb/static/termweb.js.bak +0 -168
- janito/termweb/static/termweb.js.bak.bak +0 -157
- janito/termweb/static/termweb_quickopen.js +0 -135
- janito/termweb/static/termweb_quickopen.js.bak +0 -125
- janito/tests/test_rich_utils.py +0 -44
- janito/web/__init__.py +0 -0
- janito/web/__main__.py +0 -25
- janito/web/app.py +0 -145
- janito-1.14.2.dist-info/METADATA +0 -306
- janito-1.14.2.dist-info/RECORD +0 -162
- janito-1.14.2.dist-info/licenses/LICENSE +0 -21
- /janito/{shell → cli/chat_mode/shell}/input_history.py +0 -0
- /janito/{shell/commands/session.py → cli/chat_mode/shell/session/history.py} +0 -0
- /janito/{agent/tools_utils/formatting.py → formatting.py} +0 -0
- /janito/{agent/tools_utils/gitignore_utils.py → gitignore_utils.py} +0 -0
- /janito/{agent/platform_discovery.py → platform_discovery.py} +0 -0
- /janito/{agent/tools → tools/adapters/local}/get_file_outline/__init__.py +0 -0
- /janito/{agent/tools → tools/adapters/local}/get_file_outline/markdown_outline.py +0 -0
- /janito/{agent/tools → tools/adapters/local}/search_text/__init__.py +0 -0
- /janito/{agent/tools → tools/adapters/local}/validate_file_syntax/__init__.py +0 -0
- {janito-1.14.2.dist-info → janito-2.0.0.dist-info}/WHEEL +0 -0
- {janito-1.14.2.dist-info → janito-2.0.0.dist-info}/entry_points.txt +0 -0
- {janito-1.14.2.dist-info → janito-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,167 @@
|
|
1
|
+
from collections import defaultdict, Counter
|
2
|
+
from janito.event_bus.handler import EventHandlerBase
|
3
|
+
import janito.driver_events as driver_events
|
4
|
+
import janito.report_events as report_events
|
5
|
+
import janito.tools.tool_events as tool_events
|
6
|
+
|
7
|
+
|
8
|
+
class PerformanceCollector(EventHandlerBase):
|
9
|
+
_last_request_usage = None
|
10
|
+
|
11
|
+
"""
|
12
|
+
Aggregates performance metrics and statistics from LLM driver and report events.
|
13
|
+
Collects timing, token usage, status, error, turn, content part, and tool usage data.
|
14
|
+
Also tracks request durations.
|
15
|
+
"""
|
16
|
+
|
17
|
+
def __init__(self):
|
18
|
+
super().__init__(driver_events, report_events, tool_events)
|
19
|
+
# Aggregated stats
|
20
|
+
self.total_requests = 0
|
21
|
+
self.status_counter = Counter()
|
22
|
+
self.token_usage = defaultdict(
|
23
|
+
int
|
24
|
+
) # keys: total_tokens, prompt_tokens, completion_tokens
|
25
|
+
self.error_count = 0
|
26
|
+
self.error_messages = []
|
27
|
+
self.error_exceptions = []
|
28
|
+
self.total_turns = 0
|
29
|
+
self.generation_finished_count = 0
|
30
|
+
self.content_part_count = 0
|
31
|
+
# Duration tracking
|
32
|
+
self._request_start_times = dict() # request_id -> timestamp
|
33
|
+
self._durations = [] # list of elapsed times (seconds)
|
34
|
+
# Tool stats
|
35
|
+
self.total_tool_events = 0
|
36
|
+
self.tool_names_counter = Counter()
|
37
|
+
self.tool_error_count = 0
|
38
|
+
self.tool_error_messages = []
|
39
|
+
self.tool_action_counter = Counter()
|
40
|
+
self.tool_subtype_counter = Counter()
|
41
|
+
# Raw events for reference
|
42
|
+
self._events = []
|
43
|
+
|
44
|
+
def on_RequestStarted(self, event):
|
45
|
+
self._events.append(("RequestStarted", event))
|
46
|
+
# Store the start time if possible
|
47
|
+
# Assumes 'event' has a unique .request_id and a .timestamp (in seconds)
|
48
|
+
request_id = event.request_id
|
49
|
+
timestamp = event.timestamp
|
50
|
+
if request_id is not None and timestamp is not None:
|
51
|
+
self._request_start_times[request_id] = timestamp
|
52
|
+
|
53
|
+
def on_RequestFinished(self, event):
|
54
|
+
self._events.append(("RequestFinished", event))
|
55
|
+
# Calculate and record the duration if start time is available
|
56
|
+
request_id = getattr(event, "request_id", None)
|
57
|
+
finish_time = getattr(event, "timestamp", None)
|
58
|
+
if request_id is not None and finish_time is not None:
|
59
|
+
start_time = self._request_start_times.pop(request_id, None)
|
60
|
+
if start_time is not None:
|
61
|
+
delta = finish_time - start_time
|
62
|
+
if hasattr(delta, "total_seconds"):
|
63
|
+
self._durations.append(delta.total_seconds())
|
64
|
+
else:
|
65
|
+
self._durations.append(float(delta))
|
66
|
+
self.total_requests += 1
|
67
|
+
self.status_counter[getattr(event, "status", None)] += 1
|
68
|
+
usage = getattr(event, "usage", None)
|
69
|
+
if usage:
|
70
|
+
self._last_request_usage = usage.copy()
|
71
|
+
for k, v in usage.items():
|
72
|
+
if isinstance(v, (int, float)):
|
73
|
+
self.token_usage[k] += v
|
74
|
+
# Error handling
|
75
|
+
if getattr(event, "status", None) in ("error", "cancelled"):
|
76
|
+
self.error_count += 1
|
77
|
+
self.error_messages.append(getattr(event, "error", None))
|
78
|
+
self.error_exceptions.append(getattr(event, "exception", None))
|
79
|
+
|
80
|
+
def on_GenerationFinished(self, event):
|
81
|
+
self._events.append(("GenerationFinished", event))
|
82
|
+
self.generation_finished_count += 1
|
83
|
+
self.total_turns += event.total_turns
|
84
|
+
|
85
|
+
def on_ContentPartFound(self, event):
|
86
|
+
self._events.append(("ContentPartFound", event))
|
87
|
+
self.content_part_count += 1
|
88
|
+
|
89
|
+
def on_ToolCallStarted(self, event):
|
90
|
+
self._events.append(("ToolCallStarted", event))
|
91
|
+
self.total_tool_events += 1
|
92
|
+
self.tool_names_counter[event.tool_name] += 1
|
93
|
+
|
94
|
+
def on_ReportEvent(self, event):
|
95
|
+
self._events.append(("ReportEvent", event))
|
96
|
+
# Only count errors for reporting
|
97
|
+
if event.subtype:
|
98
|
+
self.tool_subtype_counter[str(event.subtype)] += 1
|
99
|
+
if str(event.subtype).lower() == "error":
|
100
|
+
self.tool_error_count += 1
|
101
|
+
self.tool_error_messages.append(event.message)
|
102
|
+
|
103
|
+
# --- Aggregated Data Accessors ---
|
104
|
+
def get_average_duration(self):
|
105
|
+
if not self._durations:
|
106
|
+
return 0.0
|
107
|
+
return sum(self._durations) / len(self._durations)
|
108
|
+
|
109
|
+
def get_total_requests(self):
|
110
|
+
return self.total_requests
|
111
|
+
|
112
|
+
def get_status_counts(self):
|
113
|
+
return dict(self.status_counter)
|
114
|
+
|
115
|
+
def get_token_usage(self):
|
116
|
+
return dict(self.token_usage)
|
117
|
+
|
118
|
+
def get_error_count(self):
|
119
|
+
return self.error_count
|
120
|
+
|
121
|
+
def get_error_messages(self):
|
122
|
+
return list(self.error_messages)
|
123
|
+
|
124
|
+
def get_total_turns(self):
|
125
|
+
return self.total_turns
|
126
|
+
|
127
|
+
def get_average_turns(self):
|
128
|
+
if self.generation_finished_count == 0:
|
129
|
+
return 0.0
|
130
|
+
return self.total_turns / self.generation_finished_count
|
131
|
+
|
132
|
+
def get_content_part_count(self):
|
133
|
+
return self.content_part_count
|
134
|
+
|
135
|
+
# --- Tool Stats Accessors ---
|
136
|
+
def get_total_tool_events(self):
|
137
|
+
return self.total_tool_events
|
138
|
+
|
139
|
+
def get_tool_names_counter(self):
|
140
|
+
return dict(self.tool_names_counter)
|
141
|
+
|
142
|
+
def get_tool_error_count(self):
|
143
|
+
return self.tool_error_count
|
144
|
+
|
145
|
+
def get_tool_error_messages(self):
|
146
|
+
return list(self.tool_error_messages)
|
147
|
+
|
148
|
+
def get_tool_action_counter(self):
|
149
|
+
return dict(self.tool_action_counter)
|
150
|
+
|
151
|
+
def get_tool_subtype_counter(self):
|
152
|
+
return dict(self.tool_subtype_counter)
|
153
|
+
|
154
|
+
def get_all_events(self):
|
155
|
+
return list(self._events)
|
156
|
+
|
157
|
+
def get_last_request_usage(self):
|
158
|
+
"""
|
159
|
+
Returns the usage dict (tokens) from the most recent RequestFinished event, or None if not available.
|
160
|
+
"""
|
161
|
+
return self._last_request_usage.copy() if self._last_request_usage else None
|
162
|
+
|
163
|
+
def reset_last_request_usage(self):
|
164
|
+
"""
|
165
|
+
Clears the most recent usage dict. Use this (e.g. on session reset) to remove token/usage stats for toolbar.
|
166
|
+
"""
|
167
|
+
self._last_request_usage = None
|
@@ -0,0 +1,98 @@
|
|
1
|
+
"""
|
2
|
+
ProviderConfigManager: Handles reading and writing provider configuration for janito.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from janito.config import config
|
6
|
+
from janito.llm.auth import LLMAuthManager
|
7
|
+
|
8
|
+
|
9
|
+
def get_config_provider():
|
10
|
+
return config.get("provider")
|
11
|
+
|
12
|
+
|
13
|
+
def set_config_provider(provider_name):
|
14
|
+
config.file_set("provider", provider_name)
|
15
|
+
|
16
|
+
|
17
|
+
def get_config_path():
|
18
|
+
return str(config.config_path)
|
19
|
+
|
20
|
+
|
21
|
+
def set_api_key(provider, api_key):
|
22
|
+
auth_manager = LLMAuthManager()
|
23
|
+
auth_manager.set_credentials(provider, api_key)
|
24
|
+
|
25
|
+
|
26
|
+
def get_provider_config(provider):
|
27
|
+
return config.get_provider_config(provider)
|
28
|
+
|
29
|
+
|
30
|
+
def set_provider_config(provider, key, value):
|
31
|
+
# Update provider config and persist immediately
|
32
|
+
cfg = config.file_config.get("providers", {})
|
33
|
+
if provider not in cfg:
|
34
|
+
cfg[provider] = {}
|
35
|
+
cfg[provider][key] = value
|
36
|
+
config.file_config["providers"] = cfg
|
37
|
+
with open(config.config_path, "w", encoding="utf-8") as f:
|
38
|
+
json.dump(config.file_config, f, indent=2)
|
39
|
+
|
40
|
+
|
41
|
+
def set_provider_model_config(provider, model, key, value):
|
42
|
+
# Update provider-model config and persist immediately
|
43
|
+
cfg = config.file_config.get("providers", {})
|
44
|
+
if provider not in cfg:
|
45
|
+
cfg[provider] = {}
|
46
|
+
if "models" not in cfg[provider]:
|
47
|
+
cfg[provider]["models"] = {}
|
48
|
+
if model not in cfg[provider]["models"]:
|
49
|
+
cfg[provider]["models"][model] = {}
|
50
|
+
cfg[provider]["models"][model][key] = value
|
51
|
+
config.file_config["providers"] = cfg
|
52
|
+
with open(config.config_path, "w", encoding="utf-8") as f:
|
53
|
+
json.dump(config.file_config, f, indent=2)
|
54
|
+
|
55
|
+
|
56
|
+
def get_provider_model_config(provider, model):
|
57
|
+
return config.get_provider_model_config(provider, model)
|
58
|
+
|
59
|
+
|
60
|
+
def get_effective_model(provider=None, requested_model=None):
|
61
|
+
"""
|
62
|
+
Returns the best model selection according to the following precedence:
|
63
|
+
1. If requested_model is provided, use it.
|
64
|
+
2. If a provider is set and provider.model is set, use it.
|
65
|
+
3. If a global model is set, use it.
|
66
|
+
Returns None if not found.
|
67
|
+
"""
|
68
|
+
if requested_model:
|
69
|
+
return requested_model
|
70
|
+
if provider:
|
71
|
+
provider_model = config.get_provider_config(provider).get("model")
|
72
|
+
if provider_model:
|
73
|
+
return provider_model
|
74
|
+
global_model = config.get("model")
|
75
|
+
if global_model:
|
76
|
+
return global_model
|
77
|
+
return None
|
78
|
+
|
79
|
+
|
80
|
+
def get_effective_setting(provider, model, setting):
|
81
|
+
"""
|
82
|
+
Look up setting with the following order:
|
83
|
+
1. providers.{provider}.models.{model}.{setting}
|
84
|
+
2. providers.{provider}.{setting}
|
85
|
+
3. top-level {setting}
|
86
|
+
Returns None if not found.
|
87
|
+
"""
|
88
|
+
# 1. provider-model
|
89
|
+
val = config.get_provider_model_config(provider, model).get(setting)
|
90
|
+
if val is not None:
|
91
|
+
return val
|
92
|
+
# 2. provider
|
93
|
+
val = config.get_provider_config(provider).get(setting)
|
94
|
+
if val is not None:
|
95
|
+
return val
|
96
|
+
# 3. top-level
|
97
|
+
val = config.get(setting)
|
98
|
+
return val
|
@@ -0,0 +1,152 @@
|
|
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
|
+
shared_console.print(table)
|
52
|
+
|
53
|
+
def _get_provider_info(self, provider_name):
|
54
|
+
static_info = STATIC_PROVIDER_METADATA.get(provider_name, {})
|
55
|
+
maintainer_val = static_info.get("maintainer", "-")
|
56
|
+
maintainer = (
|
57
|
+
"[red]🚨 Needs maintainer[/red]"
|
58
|
+
if maintainer_val == "Needs maintainer"
|
59
|
+
else f"👤 {maintainer_val}"
|
60
|
+
)
|
61
|
+
model_names = "-"
|
62
|
+
unavailable_reason = None
|
63
|
+
skip = False
|
64
|
+
try:
|
65
|
+
provider_class = LLMProviderRegistry.get(provider_name)
|
66
|
+
creds = LLMAuthManager().get_credentials(provider_name)
|
67
|
+
provider_instance = None
|
68
|
+
instantiation_failed = False
|
69
|
+
try:
|
70
|
+
provider_instance = provider_class()
|
71
|
+
except NotImplementedError:
|
72
|
+
skip = True
|
73
|
+
unavailable_reason = "Not implemented"
|
74
|
+
model_names = f"[red]❌ Not implemented[/red]"
|
75
|
+
except Exception as e:
|
76
|
+
instantiation_failed = True
|
77
|
+
unavailable_reason = (
|
78
|
+
f"Unavailable (import error or missing dependency): {str(e)}"
|
79
|
+
)
|
80
|
+
model_names = f"[red]❌ {unavailable_reason}[/red]"
|
81
|
+
if not instantiation_failed and provider_instance is not None:
|
82
|
+
available, unavailable_reason = self._get_availability(
|
83
|
+
provider_instance
|
84
|
+
)
|
85
|
+
if (
|
86
|
+
not available
|
87
|
+
and unavailable_reason
|
88
|
+
and "not implemented" in str(unavailable_reason).lower()
|
89
|
+
):
|
90
|
+
skip = True
|
91
|
+
if available:
|
92
|
+
model_names = self._get_model_names(provider_name)
|
93
|
+
else:
|
94
|
+
model_names = f"[red]❌ {unavailable_reason}[/red]"
|
95
|
+
except Exception as import_error:
|
96
|
+
model_names = f"[red]❌ Unavailable (cannot import provider module): {str(import_error)}[/red]"
|
97
|
+
return (provider_name, maintainer, model_names, skip)
|
98
|
+
|
99
|
+
def _get_availability(self, provider_instance):
|
100
|
+
try:
|
101
|
+
available = getattr(provider_instance, "available", True)
|
102
|
+
unavailable_reason = getattr(provider_instance, "unavailable_reason", None)
|
103
|
+
except Exception as e:
|
104
|
+
available = False
|
105
|
+
unavailable_reason = f"Error reading runtime availability: {str(e)}"
|
106
|
+
return available, unavailable_reason
|
107
|
+
|
108
|
+
def _get_model_names(self, provider_name):
|
109
|
+
provider_to_specs = {
|
110
|
+
"openai": "janito.providers.openai.model_info",
|
111
|
+
"azure_openai": "janito.providers.azure_openai.model_info",
|
112
|
+
"google": "janito.providers.google.model_info",
|
113
|
+
"mistralai": "janito.providers.mistralai.model_info",
|
114
|
+
"deepseek": "janito.providers.deepseek.model_info",
|
115
|
+
}
|
116
|
+
if provider_name in provider_to_specs:
|
117
|
+
try:
|
118
|
+
mod = __import__(
|
119
|
+
provider_to_specs[provider_name], fromlist=["MODEL_SPECS"]
|
120
|
+
)
|
121
|
+
return ", ".join(mod.MODEL_SPECS.keys())
|
122
|
+
except Exception:
|
123
|
+
return "(Error)"
|
124
|
+
return "-"
|
125
|
+
|
126
|
+
def _maintainer_sort_key(self, row):
|
127
|
+
maint = row[1]
|
128
|
+
is_needs_maint = "Needs maintainer" in maint
|
129
|
+
return (is_needs_maint, row[2] != "✅ Auth")
|
130
|
+
|
131
|
+
def get_provider(self, provider_name):
|
132
|
+
"""Return the provider class for the given provider name."""
|
133
|
+
from janito.providers.registry import LLMProviderRegistry
|
134
|
+
|
135
|
+
if not provider_name:
|
136
|
+
raise ValueError("Provider name must be specified.")
|
137
|
+
return LLMProviderRegistry.get(provider_name)
|
138
|
+
|
139
|
+
def get_instance(self, provider_name, config=None):
|
140
|
+
"""Return an instance of the provider for the given provider name, optionally passing a config object."""
|
141
|
+
provider_class = self.get_provider(provider_name)
|
142
|
+
if provider_class is None:
|
143
|
+
raise ValueError(f"No provider class found for '{provider_name}'")
|
144
|
+
if config is not None:
|
145
|
+
return provider_class(config=config)
|
146
|
+
return provider_class()
|
147
|
+
|
148
|
+
|
149
|
+
# For backward compatibility
|
150
|
+
def list_providers():
|
151
|
+
"""Legacy function for listing providers, now uses ProviderRegistry class."""
|
152
|
+
ProviderRegistry().list_providers()
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Ensure all providers are registered by importing their modules
|
2
|
+
import janito.providers.openai.provider
|
3
|
+
import janito.providers.mistralai.provider
|
4
|
+
import janito.providers.google.provider
|
5
|
+
import janito.providers.azure_openai.provider
|
6
|
+
import janito.providers.anthropic.provider
|
7
|
+
import janito.providers.deepseek.provider
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from janito.llm.model import LLMModelInfo
|
2
|
+
|
3
|
+
MODEL_SPECS = {
|
4
|
+
"claude-3-opus-20240229": LLMModelInfo(
|
5
|
+
name="claude-3-opus-20240229",
|
6
|
+
max_response=200000,
|
7
|
+
default_temp=0.7,
|
8
|
+
driver="AnthropicModelDriver",
|
9
|
+
),
|
10
|
+
"claude-3-sonnet-20240229": LLMModelInfo(
|
11
|
+
name="claude-3-sonnet-20240229",
|
12
|
+
max_response=200000,
|
13
|
+
default_temp=0.7,
|
14
|
+
driver="AnthropicModelDriver",
|
15
|
+
),
|
16
|
+
"claude-3-haiku-20240307": LLMModelInfo(
|
17
|
+
name="claude-3-haiku-20240307",
|
18
|
+
max_response=200000,
|
19
|
+
default_temp=0.7,
|
20
|
+
driver="AnthropicModelDriver",
|
21
|
+
),
|
22
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from janito.llm.provider import LLMProvider
|
2
|
+
from janito.llm.model import LLMModelInfo
|
3
|
+
from janito.llm.auth import LLMAuthManager
|
4
|
+
from janito.llm.driver_config import LLMDriverConfig
|
5
|
+
from janito.tools.adapters.local.adapter import LocalToolsAdapter
|
6
|
+
from janito.providers.registry import LLMProviderRegistry
|
7
|
+
|
8
|
+
from .model_info import MODEL_SPECS
|
9
|
+
|
10
|
+
from janito.drivers.anthropic.driver import AnthropicModelDriver
|
11
|
+
|
12
|
+
available = AnthropicModelDriver.available
|
13
|
+
unavailable_reason = AnthropicModelDriver.unavailable_reason
|
14
|
+
maintainer = "Needs maintainer"
|
15
|
+
|
16
|
+
|
17
|
+
class AnthropicProvider(LLMProvider):
|
18
|
+
name = "anthropic"
|
19
|
+
maintainer = "Needs maintainer"
|
20
|
+
MODEL_SPECS = MODEL_SPECS
|
21
|
+
DEFAULT_MODEL = "claude-3-opus-20240229"
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
|
25
|
+
):
|
26
|
+
if not self.available:
|
27
|
+
self._driver = None
|
28
|
+
return
|
29
|
+
self.auth_manager = auth_manager or LLMAuthManager()
|
30
|
+
self._api_key = self.auth_manager.get_credentials(type(self).name)
|
31
|
+
self._tools_adapter = LocalToolsAdapter()
|
32
|
+
self._info = config or LLMDriverConfig(model=None)
|
33
|
+
if not self._info.model:
|
34
|
+
self._info.model = self.DEFAULT_MODEL
|
35
|
+
if not self._info.api_key:
|
36
|
+
self._info.api_key = self._api_key
|
37
|
+
self.fill_missing_device_info(self._info)
|
38
|
+
self._driver = AnthropicModelDriver(tools_adapter=self._tools_adapter)
|
39
|
+
|
40
|
+
@property
|
41
|
+
def driver(self):
|
42
|
+
if not self.available:
|
43
|
+
raise ImportError(
|
44
|
+
f"AnthropicProvider unavailable: {self.unavailable_reason}"
|
45
|
+
)
|
46
|
+
return self._driver
|
47
|
+
|
48
|
+
@property
|
49
|
+
def available(self):
|
50
|
+
return available
|
51
|
+
|
52
|
+
@property
|
53
|
+
def unavailable_reason(self):
|
54
|
+
return unavailable_reason
|
55
|
+
|
56
|
+
def create_agent(self, tools_adapter=None, agent_name: str = None, **kwargs):
|
57
|
+
from janito.llm.agent import LLMAgent
|
58
|
+
from janito.drivers.anthropic.driver import AnthropicModelDriver
|
59
|
+
|
60
|
+
# Always create a new driver with the passed-in tools_adapter
|
61
|
+
driver = AnthropicModelDriver(tools_adapter=tools_adapter)
|
62
|
+
return LLMAgent(self, tools_adapter, agent_name=agent_name, **kwargs)
|
63
|
+
|
64
|
+
|
65
|
+
LLMProviderRegistry.register(AnthropicProvider.name, AnthropicProvider)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
from janito.llm.model import LLMModelInfo
|
2
|
+
|
3
|
+
MODEL_SPECS = {
|
4
|
+
"azure_openai_deployment": LLMModelInfo(
|
5
|
+
name="azure_openai_deployment",
|
6
|
+
context="N/A",
|
7
|
+
max_input="N/A",
|
8
|
+
max_cot="N/A",
|
9
|
+
max_response="N/A",
|
10
|
+
thinking_supported=False,
|
11
|
+
default_temp=0.2,
|
12
|
+
open="azure_openai",
|
13
|
+
driver="AzureOpenAIModelDriver",
|
14
|
+
)
|
15
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
from janito.llm.provider import LLMProvider
|
2
|
+
from janito.llm.model import LLMModelInfo
|
3
|
+
from janito.llm.auth import LLMAuthManager
|
4
|
+
from janito.llm.driver_config import LLMDriverConfig
|
5
|
+
from janito.tools.adapters.local.adapter import LocalToolsAdapter
|
6
|
+
from janito.providers.registry import LLMProviderRegistry
|
7
|
+
|
8
|
+
from .model_info import MODEL_SPECS
|
9
|
+
|
10
|
+
from janito.drivers.azure_openai.driver import AzureOpenAIModelDriver
|
11
|
+
|
12
|
+
available = AzureOpenAIModelDriver.available
|
13
|
+
unavailable_reason = AzureOpenAIModelDriver.unavailable_reason
|
14
|
+
maintainer = "João Pinto <lamego.pinto@gmail.com>"
|
15
|
+
|
16
|
+
|
17
|
+
class AzureOpenAIProvider(LLMProvider):
|
18
|
+
name = "azure_openai"
|
19
|
+
maintainer = "João Pinto <lamego.pinto@gmail.com>"
|
20
|
+
MODEL_SPECS = MODEL_SPECS
|
21
|
+
DEFAULT_MODEL = "azure_openai_deployment"
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
|
25
|
+
):
|
26
|
+
if not self.available:
|
27
|
+
self._driver = None
|
28
|
+
return
|
29
|
+
self._auth_manager = auth_manager or LLMAuthManager()
|
30
|
+
self._api_key = self._auth_manager.get_credentials(type(self).name)
|
31
|
+
self._tools_adapter = LocalToolsAdapter()
|
32
|
+
self._driver_config = config or LLMDriverConfig(model=None)
|
33
|
+
if not self._driver_config.model:
|
34
|
+
self._driver_config.model = self.DEFAULT_MODEL
|
35
|
+
if not self._driver_config.api_key:
|
36
|
+
self._driver_config.api_key = self._api_key
|
37
|
+
if not self._driver_config.extra.get("api_version"):
|
38
|
+
self._driver_config.extra["api_version"] = "2023-05-15"
|
39
|
+
self.fill_missing_device_info(self._driver_config)
|
40
|
+
self._driver = AzureOpenAIModelDriver(tools_adapter=self._tools_adapter)
|
41
|
+
|
42
|
+
@property
|
43
|
+
def driver(self):
|
44
|
+
if not self.available:
|
45
|
+
raise ImportError(
|
46
|
+
f"AzureOpenAIProvider unavailable: {self.unavailable_reason}"
|
47
|
+
)
|
48
|
+
return self._driver
|
49
|
+
|
50
|
+
@property
|
51
|
+
def available(self):
|
52
|
+
return available
|
53
|
+
|
54
|
+
@property
|
55
|
+
def unavailable_reason(self):
|
56
|
+
return unavailable_reason
|
57
|
+
|
58
|
+
def create_agent(self, tools_adapter=None, agent_name: str = None, **kwargs):
|
59
|
+
from janito.llm.agent import LLMAgent
|
60
|
+
from janito.drivers.azure_openai.driver import AzureOpenAIModelDriver
|
61
|
+
|
62
|
+
# Always create a new driver with the passed-in tools_adapter
|
63
|
+
driver = AzureOpenAIModelDriver(tools_adapter=tools_adapter)
|
64
|
+
return LLMAgent(self, tools_adapter, agent_name=agent_name, **kwargs)
|
65
|
+
|
66
|
+
def execute_tool(self, tool_name: str, event_bus, *args, **kwargs):
|
67
|
+
# Use direct execution via adapter:
|
68
|
+
self._tools_adapter.event_bus = event_bus
|
69
|
+
return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
|
70
|
+
|
71
|
+
|
72
|
+
LLMProviderRegistry.register(AzureOpenAIProvider.name, AzureOpenAIProvider)
|
@@ -0,0 +1 @@
|
|
1
|
+
# Deepseek provider package marker
|
@@ -0,0 +1,16 @@
|
|
1
|
+
MODEL_SPECS = {
|
2
|
+
"deepseek-chat": {
|
3
|
+
"description": "DeepSeek Chat Model (OpenAI-compatible)",
|
4
|
+
"context_window": 8192,
|
5
|
+
"max_tokens": 4096,
|
6
|
+
"family": "deepseek",
|
7
|
+
"default": True,
|
8
|
+
},
|
9
|
+
"deepseek-coder": {
|
10
|
+
"description": "DeepSeek Coder Model (OpenAI-compatible)",
|
11
|
+
"context_window": 8192,
|
12
|
+
"max_tokens": 4096,
|
13
|
+
"family": "deepseek",
|
14
|
+
"default": False,
|
15
|
+
},
|
16
|
+
}
|