janito 2.14.0__py3-none-any.whl → 2.16.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/cli/chat_mode/session.py +42 -1
- janito/cli/cli_commands/list_drivers.py +117 -93
- janito/cli/cli_commands/list_providers_region.py +85 -0
- janito/cli/core/getters.py +7 -3
- janito/cli/main_cli.py +38 -3
- janito/cli/single_shot_mode/handler.py +43 -1
- janito/drivers/azure_openai/driver.py +14 -5
- janito/drivers/openai/driver.py +16 -5
- janito/drivers/zai/driver.py +19 -22
- janito/formatting_token.py +9 -5
- janito/llm/auth_utils.py +21 -0
- janito/providers/alibaba/provider.py +13 -9
- janito/providers/anthropic/provider.py +4 -5
- janito/providers/azure_openai/provider.py +4 -5
- janito/providers/deepseek/provider.py +4 -5
- janito/providers/google/provider.py +4 -5
- janito/providers/moonshotai/provider.py +46 -37
- janito/providers/openai/provider.py +45 -39
- janito/providers/zai/provider.py +4 -10
- janito/regions/__init__.py +16 -0
- janito/regions/cli.py +124 -0
- janito/regions/geo_utils.py +240 -0
- janito/regions/provider_regions.py +158 -0
- {janito-2.14.0.dist-info → janito-2.16.0.dist-info}/METADATA +1 -1
- {janito-2.14.0.dist-info → janito-2.16.0.dist-info}/RECORD +29 -23
- {janito-2.14.0.dist-info → janito-2.16.0.dist-info}/WHEEL +0 -0
- {janito-2.14.0.dist-info → janito-2.16.0.dist-info}/entry_points.txt +0 -0
- {janito-2.14.0.dist-info → janito-2.16.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.14.0.dist-info → janito-2.16.0.dist-info}/top_level.txt +0 -0
janito/cli/chat_mode/session.py
CHANGED
@@ -115,9 +115,15 @@ class ChatSession:
|
|
115
115
|
def _select_profile_and_role(self, args, role):
|
116
116
|
profile = getattr(args, "profile", None) if args is not None else None
|
117
117
|
role_arg = getattr(args, "role", None) if args is not None else None
|
118
|
+
python_profile = getattr(args, "python", False) if args is not None else False
|
118
119
|
profile_system_prompt = None
|
119
120
|
no_tools_mode = False
|
120
|
-
|
121
|
+
|
122
|
+
# Handle --python flag
|
123
|
+
if python_profile and profile is None and role_arg is None:
|
124
|
+
profile = "Developer with Python Tools"
|
125
|
+
|
126
|
+
if profile is None and role_arg is None and not python_profile:
|
121
127
|
try:
|
122
128
|
from janito.cli.chat_mode.session_profile_select import select_profile
|
123
129
|
|
@@ -277,6 +283,41 @@ class ChatSession:
|
|
277
283
|
else None
|
278
284
|
)
|
279
285
|
start_time = time.time()
|
286
|
+
|
287
|
+
# Print rule line with model info before processing prompt
|
288
|
+
model_name = (
|
289
|
+
self.agent.get_model_name()
|
290
|
+
if hasattr(self.agent, "get_model_name")
|
291
|
+
else "Unknown"
|
292
|
+
)
|
293
|
+
provider_name = (
|
294
|
+
self.agent.get_provider_name()
|
295
|
+
if hasattr(self.agent, "get_provider_name")
|
296
|
+
else "Unknown"
|
297
|
+
)
|
298
|
+
|
299
|
+
# Get backend hostname if available
|
300
|
+
backend_hostname = "Unknown"
|
301
|
+
if hasattr(self.agent, "driver") and self.agent.driver:
|
302
|
+
if hasattr(self.agent.driver, "config") and hasattr(
|
303
|
+
self.agent.driver.config, "base_url"
|
304
|
+
):
|
305
|
+
base_url = self.agent.driver.config.base_url
|
306
|
+
if base_url:
|
307
|
+
try:
|
308
|
+
from urllib.parse import urlparse
|
309
|
+
|
310
|
+
parsed = urlparse(base_url)
|
311
|
+
backend_hostname = parsed.netloc
|
312
|
+
except Exception:
|
313
|
+
backend_hostname = base_url
|
314
|
+
|
315
|
+
self.console.print(
|
316
|
+
Rule(
|
317
|
+
f"[bold blue]Model: {model_name} ({provider_name}) | Backend: {backend_hostname}[/bold blue]"
|
318
|
+
)
|
319
|
+
)
|
320
|
+
|
280
321
|
self._prompt_handler.run_prompt(cmd_input)
|
281
322
|
end_time = time.time()
|
282
323
|
elapsed = end_time - start_time
|
@@ -13,125 +13,149 @@ from rich.text import Text
|
|
13
13
|
console = Console()
|
14
14
|
|
15
15
|
|
16
|
+
def _detect_dependencies_from_content(content, class_name):
|
17
|
+
"""Detect dependencies from module content."""
|
18
|
+
dependencies = []
|
19
|
+
|
20
|
+
if "import openai" in content or "from openai" in content:
|
21
|
+
dependencies.append("openai")
|
22
|
+
if "import zai" in content or "from zai" in content:
|
23
|
+
dependencies.append("zai")
|
24
|
+
if "import anthropic" in content or "from anthropic" in content:
|
25
|
+
dependencies.append("anthropic")
|
26
|
+
if "import google" in content or "from google" in content:
|
27
|
+
dependencies.append("google-generativeai")
|
28
|
+
|
29
|
+
# Remove openai from zai driver dependencies
|
30
|
+
if "ZAIModelDriver" in class_name and "openai" in dependencies:
|
31
|
+
dependencies.remove("openai")
|
32
|
+
|
33
|
+
return dependencies
|
34
|
+
|
35
|
+
|
36
|
+
def _check_dependency_status(dependencies):
|
37
|
+
"""Check if dependencies are available."""
|
38
|
+
if not dependencies:
|
39
|
+
return ["No external dependencies"]
|
40
|
+
|
41
|
+
dep_status = []
|
42
|
+
for dep in dependencies:
|
43
|
+
try:
|
44
|
+
importlib.import_module(dep)
|
45
|
+
dep_status.append(f"✅ {dep}")
|
46
|
+
except ImportError:
|
47
|
+
dep_status.append(f"❌ {dep}")
|
48
|
+
|
49
|
+
return dep_status
|
50
|
+
|
51
|
+
|
52
|
+
def _get_single_driver_info(module_path, class_name):
|
53
|
+
"""Get information for a single driver."""
|
54
|
+
try:
|
55
|
+
module = importlib.import_module(module_path)
|
56
|
+
driver_class = getattr(module, class_name)
|
57
|
+
|
58
|
+
available = getattr(driver_class, "available", True)
|
59
|
+
unavailable_reason = getattr(driver_class, "unavailable_reason", None)
|
60
|
+
|
61
|
+
# Read module file to detect imports
|
62
|
+
module_file = Path(module.__file__)
|
63
|
+
with open(module_file, "r", encoding="utf-8") as f:
|
64
|
+
content = f.read()
|
65
|
+
|
66
|
+
dependencies = _detect_dependencies_from_content(content, class_name)
|
67
|
+
dep_status = _check_dependency_status(dependencies)
|
68
|
+
|
69
|
+
return {
|
70
|
+
"name": class_name,
|
71
|
+
"available": available,
|
72
|
+
"reason": unavailable_reason,
|
73
|
+
"dependencies": dep_status,
|
74
|
+
}
|
75
|
+
|
76
|
+
except (ImportError, AttributeError) as e:
|
77
|
+
return {
|
78
|
+
"name": class_name,
|
79
|
+
"module": module_path,
|
80
|
+
"available": False,
|
81
|
+
"reason": str(e),
|
82
|
+
"dependencies": ["❌ Module not found"],
|
83
|
+
}
|
84
|
+
|
85
|
+
|
16
86
|
def get_driver_info():
|
17
87
|
"""Get information about all available drivers."""
|
18
88
|
drivers = []
|
19
|
-
|
89
|
+
|
20
90
|
# Define known driver modules
|
21
91
|
driver_modules = [
|
22
92
|
("janito.drivers.openai.driver", "OpenAIModelDriver"),
|
23
93
|
("janito.drivers.azure_openai.driver", "AzureOpenAIModelDriver"),
|
24
94
|
("janito.drivers.zai.driver", "ZAIModelDriver"),
|
25
95
|
]
|
26
|
-
|
96
|
+
|
27
97
|
for module_path, class_name in driver_modules:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
driver_class = getattr(module, class_name)
|
32
|
-
|
33
|
-
# Get availability info
|
34
|
-
available = getattr(driver_class, 'available', True)
|
35
|
-
unavailable_reason = getattr(driver_class, 'unavailable_reason', None)
|
36
|
-
|
37
|
-
# Get dependencies from module imports
|
38
|
-
dependencies = []
|
39
|
-
module_file = Path(module.__file__)
|
40
|
-
|
41
|
-
# Read module file to detect imports
|
42
|
-
with open(module_file, 'r', encoding='utf-8') as f:
|
43
|
-
content = f.read()
|
44
|
-
|
45
|
-
# Simple dependency detection
|
46
|
-
if 'import openai' in content or 'from openai' in content:
|
47
|
-
dependencies.append('openai')
|
48
|
-
if 'import zai' in content or 'from zai' in content:
|
49
|
-
dependencies.append('zai')
|
50
|
-
if 'import anthropic' in content or 'from anthropic' in content:
|
51
|
-
dependencies.append('anthropic')
|
52
|
-
if 'import google' in content or 'from google' in content:
|
53
|
-
dependencies.append('google-generativeai')
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# Remove duplicates while preserving order
|
58
|
-
seen = set()
|
59
|
-
dependencies = [dep for dep in dependencies if not (dep in seen or seen.add(dep))]
|
60
|
-
|
61
|
-
# Check if dependencies are available
|
62
|
-
dep_status = []
|
63
|
-
for dep in dependencies:
|
64
|
-
try:
|
65
|
-
importlib.import_module(dep)
|
66
|
-
dep_status.append(f"✅ {dep}")
|
67
|
-
except ImportError:
|
68
|
-
dep_status.append(f"❌ {dep}")
|
69
|
-
|
70
|
-
if not dependencies:
|
71
|
-
dep_status = ["No external dependencies"]
|
72
|
-
|
73
|
-
drivers.append({
|
74
|
-
'name': class_name,
|
75
|
-
'available': available,
|
76
|
-
'reason': unavailable_reason,
|
77
|
-
'dependencies': dep_status
|
78
|
-
})
|
79
|
-
|
80
|
-
except (ImportError, AttributeError) as e:
|
81
|
-
drivers.append({
|
82
|
-
'name': class_name,
|
83
|
-
'module': module_path,
|
84
|
-
'available': False,
|
85
|
-
'reason': str(e),
|
86
|
-
'dependencies': ["❌ Module not found"]
|
87
|
-
})
|
88
|
-
|
98
|
+
driver_info = _get_single_driver_info(module_path, class_name)
|
99
|
+
drivers.append(driver_info)
|
100
|
+
|
89
101
|
return drivers
|
90
102
|
|
91
103
|
|
92
|
-
def
|
93
|
-
"""
|
94
|
-
drivers = get_driver_info()
|
95
|
-
|
96
|
-
if not drivers:
|
97
|
-
console.print("[red]No drivers found[/red]")
|
98
|
-
return
|
99
|
-
|
100
|
-
# Create table
|
104
|
+
def _create_driver_table(drivers):
|
105
|
+
"""Create and populate the drivers table."""
|
101
106
|
table = Table(title="Available LLM Drivers")
|
102
107
|
table.add_column("Driver", style="cyan", no_wrap=True)
|
103
108
|
table.add_column("Status", style="bold")
|
104
109
|
table.add_column("Dependencies", style="yellow")
|
105
|
-
|
110
|
+
|
106
111
|
for driver in drivers:
|
107
|
-
name = driver[
|
108
|
-
|
109
|
-
if driver[
|
112
|
+
name = driver["name"]
|
113
|
+
|
114
|
+
if driver["available"]:
|
110
115
|
status = "[green]✅ Available[/green]"
|
111
|
-
if driver[
|
116
|
+
if driver["reason"]:
|
112
117
|
status = f"[yellow]⚠️ Available ({driver['reason']})[/yellow]"
|
113
118
|
else:
|
114
119
|
status = f"[red]❌ Unavailable[/red]"
|
115
|
-
if driver[
|
120
|
+
if driver["reason"]:
|
116
121
|
status = f"[red]❌ {driver['reason']}[/red]"
|
117
|
-
|
118
|
-
deps = "\n".join(driver[
|
119
|
-
|
122
|
+
|
123
|
+
deps = "\n".join(driver["dependencies"])
|
120
124
|
table.add_row(name, status, deps)
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
125
|
+
|
126
|
+
return table
|
127
|
+
|
128
|
+
|
129
|
+
def _get_missing_dependencies(drivers):
|
130
|
+
"""Get list of missing dependencies."""
|
131
|
+
missing_deps = []
|
127
132
|
for driver in drivers:
|
128
|
-
for dep_status in driver[
|
129
|
-
if dep_status.startswith(
|
130
|
-
|
131
|
-
|
133
|
+
for dep_status in driver["dependencies"]:
|
134
|
+
if dep_status.startswith("❌"):
|
135
|
+
dep_name = dep_status.split()[1]
|
136
|
+
if dep_name not in missing_deps:
|
137
|
+
missing_deps.append(dep_name)
|
138
|
+
return missing_deps
|
139
|
+
|
140
|
+
|
141
|
+
def handle_list_drivers(args=None):
|
142
|
+
"""List all available LLM drivers with their status and dependencies."""
|
143
|
+
drivers = get_driver_info()
|
144
|
+
|
145
|
+
if not drivers:
|
146
|
+
console.print("[red]No drivers found[/red]")
|
147
|
+
return
|
148
|
+
|
149
|
+
table = _create_driver_table(drivers)
|
150
|
+
console.print(table)
|
151
|
+
|
152
|
+
# Installation help - only show for missing dependencies
|
153
|
+
missing_deps = _get_missing_dependencies(drivers)
|
132
154
|
if missing_deps:
|
133
|
-
console.print(
|
155
|
+
console.print(
|
156
|
+
f"\n[dim]💡 Install missing deps: pip install {' '.join(missing_deps)}[/dim]"
|
157
|
+
)
|
134
158
|
|
135
159
|
|
136
160
|
if __name__ == "__main__":
|
137
|
-
handle_list_drivers()
|
161
|
+
handle_list_drivers()
|
@@ -0,0 +1,85 @@
|
|
1
|
+
"""
|
2
|
+
CLI Command: List providers with their regional API information
|
3
|
+
"""
|
4
|
+
|
5
|
+
import json
|
6
|
+
from typing import Dict, List
|
7
|
+
from rich.console import Console
|
8
|
+
from rich.table import Table
|
9
|
+
from rich.panel import Panel
|
10
|
+
|
11
|
+
from janito.regions.provider_regions import PROVIDER_REGIONS, get_all_providers
|
12
|
+
from janito.regions.geo_utils import get_region_info
|
13
|
+
|
14
|
+
console = Console()
|
15
|
+
|
16
|
+
|
17
|
+
def handle_list_providers_region(args=None):
|
18
|
+
"""List all providers with their regional API information."""
|
19
|
+
|
20
|
+
# Get user location info
|
21
|
+
user_info = get_region_info()
|
22
|
+
user_region = user_info["major_region"]
|
23
|
+
|
24
|
+
# Get all providers
|
25
|
+
providers = get_all_providers()
|
26
|
+
|
27
|
+
# Create table
|
28
|
+
table = Table(title="LLM Providers by Region")
|
29
|
+
table.add_column("Provider", style="cyan", no_wrap=True)
|
30
|
+
table.add_column("Region", style="green")
|
31
|
+
table.add_column("Endpoint", style="bright_white")
|
32
|
+
|
33
|
+
for provider in sorted(providers):
|
34
|
+
regions = PROVIDER_REGIONS.get(provider, [])
|
35
|
+
if not regions:
|
36
|
+
table.add_row(provider, "N/A", "N/A", "N/A", "N/A")
|
37
|
+
continue
|
38
|
+
|
39
|
+
# Find the best region for the user
|
40
|
+
best_region = None
|
41
|
+
for region in regions:
|
42
|
+
if region.region_code.startswith(user_region):
|
43
|
+
best_region = region
|
44
|
+
break
|
45
|
+
|
46
|
+
# If no exact match, use first available
|
47
|
+
if not best_region:
|
48
|
+
best_region = regions[0]
|
49
|
+
|
50
|
+
# Extract 2-letter region code
|
51
|
+
if provider == "azure-openai":
|
52
|
+
region_code = "ALL"
|
53
|
+
else:
|
54
|
+
region_code = (
|
55
|
+
user_region
|
56
|
+
if any(r.region_code.startswith(user_region) for r in regions)
|
57
|
+
else (
|
58
|
+
"APAC"
|
59
|
+
if best_region.region_code == "ASIA-PACIFIC"
|
60
|
+
else best_region.region_code[:2]
|
61
|
+
)
|
62
|
+
)
|
63
|
+
|
64
|
+
table.add_row(
|
65
|
+
provider,
|
66
|
+
region_code,
|
67
|
+
best_region.endpoint,
|
68
|
+
)
|
69
|
+
|
70
|
+
console.print(table)
|
71
|
+
|
72
|
+
# Show user location info
|
73
|
+
console.print(
|
74
|
+
f"\n[dim]Your location: {user_info['country_code']} ({user_region})[/dim]"
|
75
|
+
)
|
76
|
+
console.print(f"[dim]Detection source: {user_info['source']}[/dim]")
|
77
|
+
|
78
|
+
# Show region mapping info
|
79
|
+
console.print(
|
80
|
+
"\n[dim]Regions: US (United States), EU (Europe), CN (China), CH (Switzerland), APAC (Asia Pacific)[/dim]"
|
81
|
+
)
|
82
|
+
|
83
|
+
|
84
|
+
if __name__ == "__main__":
|
85
|
+
handle_list_providers_region()
|
janito/cli/core/getters.py
CHANGED
@@ -8,6 +8,8 @@ from janito.cli.cli_commands.list_tools import handle_list_tools
|
|
8
8
|
from janito.cli.cli_commands.show_config import handle_show_config
|
9
9
|
from janito.cli.cli_commands.list_config import handle_list_config
|
10
10
|
from janito.cli.cli_commands.list_drivers import handle_list_drivers
|
11
|
+
from janito.regions.cli import handle_region_info
|
12
|
+
from janito.cli.cli_commands.list_providers_region import handle_list_providers_region
|
11
13
|
from functools import partial
|
12
14
|
from janito.provider_registry import ProviderRegistry
|
13
15
|
|
@@ -19,6 +21,8 @@ GETTER_KEYS = [
|
|
19
21
|
"list_tools",
|
20
22
|
"list_config",
|
21
23
|
"list_drivers",
|
24
|
+
"region_info",
|
25
|
+
"list_providers_region",
|
22
26
|
]
|
23
27
|
|
24
28
|
|
@@ -45,9 +49,9 @@ def handle_getter(args, config_mgr=None):
|
|
45
49
|
"show_config": partial(handle_show_config, args),
|
46
50
|
"list_config": partial(handle_list_config, args),
|
47
51
|
"list_drivers": partial(handle_list_drivers, args),
|
52
|
+
"region_info": partial(handle_region_info, args),
|
53
|
+
"list_providers_region": partial(handle_list_providers_region, args),
|
48
54
|
}
|
49
55
|
for arg in GETTER_KEYS:
|
50
56
|
if getattr(args, arg, False) and arg in GETTER_DISPATCH:
|
51
|
-
GETTER_DISPATCH[arg]()
|
52
|
-
import sys
|
53
|
-
sys.exit(0)
|
57
|
+
return GETTER_DISPATCH[arg]()
|
janito/cli/main_cli.py
CHANGED
@@ -36,6 +36,13 @@ definition = [
|
|
36
36
|
"default": None,
|
37
37
|
},
|
38
38
|
),
|
39
|
+
(
|
40
|
+
["--python"],
|
41
|
+
{
|
42
|
+
"action": "store_true",
|
43
|
+
"help": "Start with the Python developer profile (equivalent to --profile 'Developer with Python Tools')",
|
44
|
+
},
|
45
|
+
),
|
39
46
|
(
|
40
47
|
["--role"],
|
41
48
|
{
|
@@ -119,7 +126,24 @@ definition = [
|
|
119
126
|
),
|
120
127
|
(
|
121
128
|
["--list-drivers"],
|
122
|
-
{
|
129
|
+
{
|
130
|
+
"action": "store_true",
|
131
|
+
"help": "List available LLM drivers and their dependencies",
|
132
|
+
},
|
133
|
+
),
|
134
|
+
(
|
135
|
+
["--region-info"],
|
136
|
+
{
|
137
|
+
"action": "store_true",
|
138
|
+
"help": "Show current region information and location",
|
139
|
+
},
|
140
|
+
),
|
141
|
+
(
|
142
|
+
["--list-providers-region"],
|
143
|
+
{
|
144
|
+
"action": "store_true",
|
145
|
+
"help": "List all providers with their regional API information",
|
146
|
+
},
|
123
147
|
),
|
124
148
|
(
|
125
149
|
["-l", "--list-models"],
|
@@ -192,6 +216,7 @@ MODIFIER_KEYS = [
|
|
192
216
|
"model",
|
193
217
|
"role",
|
194
218
|
"profile",
|
219
|
+
"python",
|
195
220
|
"system",
|
196
221
|
"temperature",
|
197
222
|
"verbose",
|
@@ -211,6 +236,8 @@ GETTER_KEYS = [
|
|
211
236
|
"list_tools",
|
212
237
|
"list_config",
|
213
238
|
"list_drivers",
|
239
|
+
"region_info",
|
240
|
+
"list_providers_region",
|
214
241
|
]
|
215
242
|
|
216
243
|
|
@@ -327,7 +354,14 @@ class JanitoCLI:
|
|
327
354
|
if self._run_set_mode():
|
328
355
|
return
|
329
356
|
# Special handling: provider is not required for list_providers, list_tools, show_config, list_drivers
|
330
|
-
if run_mode == RunMode.GET
|
357
|
+
if run_mode == RunMode.GET and (
|
358
|
+
self.args.list_providers
|
359
|
+
or self.args.list_tools
|
360
|
+
or self.args.list_profiles
|
361
|
+
or self.args.show_config
|
362
|
+
or self.args.list_config
|
363
|
+
or self.args.list_drivers
|
364
|
+
):
|
331
365
|
self._maybe_print_verbose_provider_model()
|
332
366
|
handle_getter(self.args)
|
333
367
|
return
|
@@ -363,7 +397,8 @@ class JanitoCLI:
|
|
363
397
|
agent_role,
|
364
398
|
verbose_tools=self.args.verbose_tools,
|
365
399
|
)
|
366
|
-
|
400
|
+
elif run_mode == RunMode.GET:
|
401
|
+
handle_getter(self.args)
|
367
402
|
|
368
403
|
def _run_set_mode(self):
|
369
404
|
if handle_api_key_set(self.args):
|
@@ -24,6 +24,11 @@ class PromptHandler:
|
|
24
24
|
self.llm_driver_config = llm_driver_config
|
25
25
|
self.role = role
|
26
26
|
# Instantiate agent together with prompt handler using the shared helper
|
27
|
+
# Handle --python flag for single shot mode
|
28
|
+
profile = getattr(args, "profile", None)
|
29
|
+
if profile is None and getattr(args, "python", False):
|
30
|
+
profile = "Developer with Python Tools"
|
31
|
+
|
27
32
|
self.agent, self.generic_handler = setup_agent_and_prompt_handler(
|
28
33
|
args=args,
|
29
34
|
provider_instance=provider_instance,
|
@@ -32,7 +37,7 @@ class PromptHandler:
|
|
32
37
|
verbose_tools=getattr(args, "verbose_tools", False),
|
33
38
|
verbose_agent=getattr(args, "verbose_agent", False),
|
34
39
|
allowed_permissions=allowed_permissions,
|
35
|
-
profile=
|
40
|
+
profile=profile,
|
36
41
|
)
|
37
42
|
|
38
43
|
def handle(self) -> None:
|
@@ -52,6 +57,43 @@ class PromptHandler:
|
|
52
57
|
|
53
58
|
try:
|
54
59
|
start_time = time.time()
|
60
|
+
|
61
|
+
# Print rule line with model info before processing prompt
|
62
|
+
model_name = (
|
63
|
+
self.agent.get_model_name()
|
64
|
+
if hasattr(self.agent, "get_model_name")
|
65
|
+
else "Unknown"
|
66
|
+
)
|
67
|
+
provider_name = (
|
68
|
+
self.agent.get_provider_name()
|
69
|
+
if hasattr(self.agent, "get_provider_name")
|
70
|
+
else "Unknown"
|
71
|
+
)
|
72
|
+
|
73
|
+
# Get backend hostname if available
|
74
|
+
backend_hostname = "Unknown"
|
75
|
+
if hasattr(self.agent, "driver") and self.agent.driver:
|
76
|
+
if hasattr(self.agent.driver, "config") and hasattr(
|
77
|
+
self.agent.driver.config, "base_url"
|
78
|
+
):
|
79
|
+
base_url = self.agent.driver.config.base_url
|
80
|
+
if base_url:
|
81
|
+
try:
|
82
|
+
from urllib.parse import urlparse
|
83
|
+
|
84
|
+
parsed = urlparse(base_url)
|
85
|
+
backend_hostname = parsed.netloc
|
86
|
+
except Exception:
|
87
|
+
backend_hostname = base_url
|
88
|
+
|
89
|
+
from rich.rule import Rule
|
90
|
+
|
91
|
+
shared_console.print(
|
92
|
+
Rule(
|
93
|
+
f"[bold blue]Model: {model_name} ({provider_name}) | Backend: {backend_hostname}[/bold blue]"
|
94
|
+
)
|
95
|
+
)
|
96
|
+
|
55
97
|
self.generic_handler.handle_prompt(
|
56
98
|
sanitized,
|
57
99
|
args=self.args,
|
@@ -6,6 +6,16 @@ from janito.llm.driver_config import LLMDriverConfig
|
|
6
6
|
|
7
7
|
|
8
8
|
class AzureOpenAIModelDriver(OpenAIModelDriver):
|
9
|
+
# Check if required dependencies are available
|
10
|
+
try:
|
11
|
+
from openai import AzureOpenAI
|
12
|
+
|
13
|
+
available = True
|
14
|
+
unavailable_reason = None
|
15
|
+
except ImportError as e:
|
16
|
+
available = False
|
17
|
+
unavailable_reason = f"Missing dependency: {str(e)}"
|
18
|
+
|
9
19
|
def start(self, *args, **kwargs):
|
10
20
|
# Ensure azure_deployment_name is set before starting
|
11
21
|
config = getattr(self, "config", None)
|
@@ -64,11 +74,10 @@ class AzureOpenAIModelDriver(OpenAIModelDriver):
|
|
64
74
|
def _instantiate_openai_client(self, config):
|
65
75
|
try:
|
66
76
|
if not config.api_key:
|
67
|
-
provider_name = getattr(self,
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
raise ValueError(f"API key is required for provider '{provider_name}'")
|
77
|
+
provider_name = getattr(self, "provider_name", "Azure OpenAI")
|
78
|
+
from janito.llm.auth_utils import handle_missing_api_key
|
79
|
+
|
80
|
+
handle_missing_api_key(provider_name, "AZURE_OPENAI_API_KEY")
|
72
81
|
|
73
82
|
from openai import AzureOpenAI
|
74
83
|
|
janito/drivers/openai/driver.py
CHANGED
@@ -16,6 +16,16 @@ import openai
|
|
16
16
|
|
17
17
|
|
18
18
|
class OpenAIModelDriver(LLMDriver):
|
19
|
+
# Check if required dependencies are available
|
20
|
+
try:
|
21
|
+
import openai
|
22
|
+
|
23
|
+
available = True
|
24
|
+
unavailable_reason = None
|
25
|
+
except ImportError as e:
|
26
|
+
available = False
|
27
|
+
unavailable_reason = f"Missing dependency: {str(e)}"
|
28
|
+
|
19
29
|
def _get_message_from_result(self, result):
|
20
30
|
"""Extract the message object from the provider result (OpenAI-specific)."""
|
21
31
|
if hasattr(result, "choices") and result.choices:
|
@@ -248,11 +258,12 @@ class OpenAIModelDriver(LLMDriver):
|
|
248
258
|
def _instantiate_openai_client(self, config):
|
249
259
|
try:
|
250
260
|
if not config.api_key:
|
251
|
-
provider_name = getattr(self,
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
261
|
+
provider_name = getattr(self, "provider_name", "OpenAI-compatible")
|
262
|
+
from janito.llm.auth_utils import handle_missing_api_key
|
263
|
+
|
264
|
+
handle_missing_api_key(
|
265
|
+
provider_name, f"{provider_name.upper()}_API_KEY"
|
266
|
+
)
|
256
267
|
|
257
268
|
api_key_display = str(config.api_key)
|
258
269
|
if api_key_display and len(api_key_display) > 8:
|