janito 2.3.0__py3-none-any.whl → 2.3.1__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 -6
- janito/cli/chat_mode/shell/autocomplete.py +21 -21
- janito/cli/chat_mode/shell/commands/clear.py +12 -12
- janito/cli/chat_mode/shell/commands/multi.py +51 -51
- janito/cli/chat_mode/shell/input_history.py +62 -62
- janito/cli/cli_commands/list_models.py +35 -35
- janito/cli/cli_commands/list_providers.py +9 -9
- janito/cli/cli_commands/list_tools.py +53 -53
- janito/cli/cli_commands/model_selection.py +50 -50
- janito/cli/cli_commands/model_utils.py +95 -95
- janito/cli/cli_commands/set_api_key.py +19 -19
- janito/cli/cli_commands/show_config.py +51 -51
- janito/cli/cli_commands/show_system_prompt.py +62 -62
- janito/cli/core/__init__.py +4 -4
- janito/cli/core/event_logger.py +59 -59
- janito/cli/core/getters.py +33 -33
- janito/cli/core/unsetters.py +54 -54
- janito/cli/single_shot_mode/__init__.py +6 -6
- janito/config.py +5 -5
- janito/config_manager.py +112 -112
- janito/drivers/anthropic/driver.py +113 -113
- janito/formatting_token.py +54 -54
- janito/i18n/__init__.py +35 -35
- janito/i18n/messages.py +23 -23
- janito/i18n/pt.py +47 -47
- janito/llm/__init__.py +5 -5
- janito/llm/agent.py +443 -443
- janito/llm/auth.py +63 -63
- janito/llm/driver_config_builder.py +34 -34
- janito/llm/driver_input.py +12 -12
- janito/llm/message_parts.py +60 -60
- janito/llm/model.py +38 -38
- janito/llm/provider.py +196 -196
- janito/provider_registry.py +176 -176
- janito/providers/anthropic/model_info.py +22 -22
- janito/providers/anthropic/provider.py +2 -0
- janito/providers/azure_openai/model_info.py +16 -16
- janito/providers/azure_openai/provider.py +3 -0
- janito/providers/deepseek/__init__.py +1 -1
- janito/providers/deepseek/model_info.py +16 -16
- janito/providers/deepseek/provider.py +94 -91
- janito/providers/google/provider.py +3 -0
- janito/providers/mistralai/provider.py +3 -0
- janito/providers/openai/provider.py +4 -0
- janito/tools/adapters/__init__.py +1 -1
- janito/tools/adapters/local/ask_user.py +102 -102
- janito/tools/adapters/local/copy_file.py +84 -84
- janito/tools/adapters/local/create_directory.py +69 -69
- janito/tools/adapters/local/create_file.py +82 -82
- janito/tools/adapters/local/fetch_url.py +97 -97
- janito/tools/adapters/local/find_files.py +138 -138
- janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
- janito/tools/adapters/local/get_file_outline/core.py +117 -117
- janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
- janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
- janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
- janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
- janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
- janito/tools/adapters/local/python_code_run.py +166 -166
- janito/tools/adapters/local/python_command_run.py +164 -164
- janito/tools/adapters/local/python_file_run.py +163 -163
- janito/tools/adapters/local/run_bash_command.py +176 -176
- janito/tools/adapters/local/run_powershell_command.py +219 -219
- janito/tools/adapters/local/search_text/__init__.py +1 -1
- janito/tools/adapters/local/search_text/core.py +201 -201
- janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
- janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
- janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
- janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
- janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
- janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
- janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
- janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
- janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
- janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
- janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
- janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
- janito/tools/adapters/local/view_file.py +167 -167
- janito/tools/inspect_registry.py +17 -17
- janito/tools/tool_base.py +105 -105
- janito/tools/tool_events.py +58 -58
- janito/tools/tool_run_exception.py +12 -12
- janito/tools/tool_use_tracker.py +81 -81
- janito/tools/tool_utils.py +45 -45
- janito/tools/tools_schema.py +104 -104
- janito/version.py +4 -4
- {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/METADATA +390 -388
- {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/RECORD +93 -93
- {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/WHEEL +0 -0
- {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/entry_points.txt +0 -0
- {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/licenses/LICENSE +0 -0
- {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/top_level.txt +0 -0
janito/llm/provider.py
CHANGED
@@ -1,196 +1,196 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
import importlib
|
3
|
-
from janito.llm.driver import LLMDriver
|
4
|
-
|
5
|
-
|
6
|
-
class LLMProvider(ABC):
|
7
|
-
def create_driver(self):
|
8
|
-
"""
|
9
|
-
Returns a new instance of the configured driver for this provider.
|
10
|
-
Subclasses must implement this method.
|
11
|
-
"""
|
12
|
-
raise NotImplementedError(
|
13
|
-
"LLMProvider subclasses must implement create_driver()."
|
14
|
-
)
|
15
|
-
|
16
|
-
"""
|
17
|
-
Abstract base class for Large Language Model (LLM) providers.
|
18
|
-
|
19
|
-
Provider Usage and Driver Communication Flow:
|
20
|
-
1. Provider class is selected (e.g., OpenAIProvider, MistralProvider).
|
21
|
-
2. An instance of the provider is created. This instance is bound to a specific configuration (LLMDriverConfig) containing model, credentials, etc.
|
22
|
-
3. All drivers created by that provider instance are associated with the bound config.
|
23
|
-
4. To communicate with an LLM, call create_driver() on the provider instance, which yields a driver configured for the attached config. Every driver created via this method inherits the provider's configuration.
|
24
|
-
|
25
|
-
Key: You do not create/configure a driver directly—always go through the provider to ensure correct configuration binding to the provider instance.
|
26
|
-
|
27
|
-
Subclasses must implement the core interface for interacting with LLM APIs and define `provider_name` as a class attribute.
|
28
|
-
"""
|
29
|
-
|
30
|
-
name: str = None # Must be set on subclasses
|
31
|
-
DEFAULT_MODEL: str = None # Should be set by subclasses
|
32
|
-
|
33
|
-
def __init_subclass__(cls, **kwargs):
|
34
|
-
super().__init_subclass__(**kwargs)
|
35
|
-
if (
|
36
|
-
not hasattr(cls, "name")
|
37
|
-
or not isinstance(getattr(cls, "name"), str)
|
38
|
-
or not cls.name
|
39
|
-
):
|
40
|
-
raise TypeError(
|
41
|
-
f"Class {cls.__name__} must define a class attribute 'name' (non-empty str)"
|
42
|
-
)
|
43
|
-
if (
|
44
|
-
not hasattr(cls, "DEFAULT_MODEL")
|
45
|
-
or getattr(cls, "DEFAULT_MODEL", None) is None
|
46
|
-
):
|
47
|
-
raise TypeError(
|
48
|
-
f"Class {cls.__name__} must define a class attribute 'DEFAULT_MODEL' (non-empty str)"
|
49
|
-
)
|
50
|
-
|
51
|
-
def fill_missing_device_info(self, config):
|
52
|
-
"""
|
53
|
-
Fill missing LLMDriverConfig fields (max_tokens, temperature, etc) from MODEL_SPECS for the chosen model.
|
54
|
-
Mutates the config in place.
|
55
|
-
"""
|
56
|
-
if not hasattr(self, "MODEL_SPECS"):
|
57
|
-
return
|
58
|
-
model_name = getattr(config, "model", None) or getattr(
|
59
|
-
self, "DEFAULT_MODEL", None
|
60
|
-
)
|
61
|
-
model_info = self.MODEL_SPECS.get(model_name)
|
62
|
-
if not model_info:
|
63
|
-
return
|
64
|
-
# Handle common fields from model_info
|
65
|
-
spec_dict = (
|
66
|
-
model_info.to_dict() if hasattr(model_info, "to_dict") else dict(model_info)
|
67
|
-
)
|
68
|
-
if (
|
69
|
-
hasattr(config, "max_tokens")
|
70
|
-
and getattr(config, "max_tokens", None) is None
|
71
|
-
):
|
72
|
-
val = spec_dict.get("max_tokens") or spec_dict.get("max_response")
|
73
|
-
if val is not None:
|
74
|
-
try:
|
75
|
-
config.max_tokens = int(val)
|
76
|
-
except Exception:
|
77
|
-
pass
|
78
|
-
if (
|
79
|
-
hasattr(config, "temperature")
|
80
|
-
and getattr(config, "temperature", None) is None
|
81
|
-
):
|
82
|
-
val = spec_dict.get("temperature")
|
83
|
-
if val is None:
|
84
|
-
val = spec_dict.get("default_temp")
|
85
|
-
if val is not None:
|
86
|
-
try:
|
87
|
-
config.temperature = float(val)
|
88
|
-
except Exception:
|
89
|
-
pass
|
90
|
-
|
91
|
-
@property
|
92
|
-
@abstractmethod
|
93
|
-
def driver(self) -> LLMDriver:
|
94
|
-
pass
|
95
|
-
|
96
|
-
def is_model_available(self, model_name):
|
97
|
-
"""
|
98
|
-
Returns True if the given model is available for this provider.
|
99
|
-
Default implementation checks MODEL_SPECS; override for dynamic providers.
|
100
|
-
"""
|
101
|
-
if not hasattr(self, "MODEL_SPECS"):
|
102
|
-
return False
|
103
|
-
return model_name in self.MODEL_SPECS
|
104
|
-
|
105
|
-
def get_model_info(self, model_name=None):
|
106
|
-
"""
|
107
|
-
Return the info dict for a given model (driver, params, etc). If model_name is None, return all model info dicts.
|
108
|
-
MODEL_SPECS must be dict[str, LLMModelInfo].
|
109
|
-
"""
|
110
|
-
if not hasattr(self, "MODEL_SPECS"):
|
111
|
-
raise NotImplementedError(
|
112
|
-
"This provider does not have a MODEL_SPECS attribute."
|
113
|
-
)
|
114
|
-
if model_name is None:
|
115
|
-
return {
|
116
|
-
name: model_info.to_dict()
|
117
|
-
for name, model_info in self.MODEL_SPECS.items()
|
118
|
-
}
|
119
|
-
if model_name in self.MODEL_SPECS:
|
120
|
-
return self.MODEL_SPECS[model_name].to_dict()
|
121
|
-
return None
|
122
|
-
|
123
|
-
def _validate_model_specs(self):
|
124
|
-
if not hasattr(self, "MODEL_SPECS"):
|
125
|
-
raise NotImplementedError(
|
126
|
-
"This provider does not have a MODEL_SPECS attribute."
|
127
|
-
)
|
128
|
-
|
129
|
-
def _get_model_name_from_config(self, config):
|
130
|
-
return (config or {}).get("model_name", getattr(self, "DEFAULT_MODEL", None))
|
131
|
-
|
132
|
-
def _get_model_spec_entry(self, model_name):
|
133
|
-
spec = self.MODEL_SPECS.get(model_name, None)
|
134
|
-
if spec is None:
|
135
|
-
raise ValueError(f"Model '{model_name}' not found in MODEL_SPECS.")
|
136
|
-
return spec
|
137
|
-
|
138
|
-
def _get_driver_name_from_spec(self, spec):
|
139
|
-
driver_name = None
|
140
|
-
if hasattr(spec, "driver") and spec.driver:
|
141
|
-
driver_name = spec.driver
|
142
|
-
elif hasattr(spec, "other") and isinstance(spec.other, dict):
|
143
|
-
driver_name = spec.other.get("driver", None)
|
144
|
-
return driver_name
|
145
|
-
|
146
|
-
def _resolve_driver_class(self, driver_name):
|
147
|
-
if not driver_name:
|
148
|
-
raise NotImplementedError(
|
149
|
-
"No driver class found or specified for this MODEL_SPECS entry."
|
150
|
-
)
|
151
|
-
module_root = "janito.drivers"
|
152
|
-
probable_path = None
|
153
|
-
mapping = {
|
154
|
-
"OpenAIResponsesModelDriver": "openai_responses.driver",
|
155
|
-
"OpenAIModelDriver": "openai.driver",
|
156
|
-
"AzureOpenAIModelDriver": "azure_openai.driver",
|
157
|
-
"GoogleGenaiModelDriver": "google_genai.driver",
|
158
|
-
}
|
159
|
-
if driver_name in mapping:
|
160
|
-
probable_path = mapping[driver_name]
|
161
|
-
module_path = f"{module_root}.{probable_path}"
|
162
|
-
mod = importlib.import_module(module_path)
|
163
|
-
return getattr(mod, driver_name)
|
164
|
-
# Attempt dynamic fallback based on convention
|
165
|
-
if driver_name.endswith("ModelDriver"):
|
166
|
-
base = driver_name[: -len("ModelDriver")]
|
167
|
-
mod_name = base.replace("_", "").lower()
|
168
|
-
module_path = f"{module_root}.{mod_name}.driver"
|
169
|
-
try:
|
170
|
-
mod = importlib.import_module(module_path)
|
171
|
-
return getattr(mod, driver_name)
|
172
|
-
except Exception:
|
173
|
-
pass
|
174
|
-
raise NotImplementedError(
|
175
|
-
"No driver class found for driver_name: {}".format(driver_name)
|
176
|
-
)
|
177
|
-
|
178
|
-
def _validate_required_config(self, driver_class, config, driver_name):
|
179
|
-
required = getattr(driver_class, "required_config", None)
|
180
|
-
if required:
|
181
|
-
missing = [
|
182
|
-
k
|
183
|
-
for k in required
|
184
|
-
if not config or k not in config or config.get(k) in (None, "")
|
185
|
-
]
|
186
|
-
if missing:
|
187
|
-
raise ValueError(
|
188
|
-
f"Missing required config for {driver_name}: {', '.join(missing)}"
|
189
|
-
)
|
190
|
-
|
191
|
-
def create_agent(self, tools_adapter=None, agent_name: str = None, **kwargs):
|
192
|
-
from janito.llm.agent import LLMAgent
|
193
|
-
|
194
|
-
# Dynamically create driver if supported, else fallback to existing.
|
195
|
-
driver = self.driver
|
196
|
-
return LLMAgent(self, tools_adapter, agent_name=agent_name, **kwargs)
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import importlib
|
3
|
+
from janito.llm.driver import LLMDriver
|
4
|
+
|
5
|
+
|
6
|
+
class LLMProvider(ABC):
|
7
|
+
def create_driver(self):
|
8
|
+
"""
|
9
|
+
Returns a new instance of the configured driver for this provider.
|
10
|
+
Subclasses must implement this method.
|
11
|
+
"""
|
12
|
+
raise NotImplementedError(
|
13
|
+
"LLMProvider subclasses must implement create_driver()."
|
14
|
+
)
|
15
|
+
|
16
|
+
"""
|
17
|
+
Abstract base class for Large Language Model (LLM) providers.
|
18
|
+
|
19
|
+
Provider Usage and Driver Communication Flow:
|
20
|
+
1. Provider class is selected (e.g., OpenAIProvider, MistralProvider).
|
21
|
+
2. An instance of the provider is created. This instance is bound to a specific configuration (LLMDriverConfig) containing model, credentials, etc.
|
22
|
+
3. All drivers created by that provider instance are associated with the bound config.
|
23
|
+
4. To communicate with an LLM, call create_driver() on the provider instance, which yields a driver configured for the attached config. Every driver created via this method inherits the provider's configuration.
|
24
|
+
|
25
|
+
Key: You do not create/configure a driver directly—always go through the provider to ensure correct configuration binding to the provider instance.
|
26
|
+
|
27
|
+
Subclasses must implement the core interface for interacting with LLM APIs and define `provider_name` as a class attribute.
|
28
|
+
"""
|
29
|
+
|
30
|
+
name: str = None # Must be set on subclasses
|
31
|
+
DEFAULT_MODEL: str = None # Should be set by subclasses
|
32
|
+
|
33
|
+
def __init_subclass__(cls, **kwargs):
|
34
|
+
super().__init_subclass__(**kwargs)
|
35
|
+
if (
|
36
|
+
not hasattr(cls, "name")
|
37
|
+
or not isinstance(getattr(cls, "name"), str)
|
38
|
+
or not cls.name
|
39
|
+
):
|
40
|
+
raise TypeError(
|
41
|
+
f"Class {cls.__name__} must define a class attribute 'name' (non-empty str)"
|
42
|
+
)
|
43
|
+
if (
|
44
|
+
not hasattr(cls, "DEFAULT_MODEL")
|
45
|
+
or getattr(cls, "DEFAULT_MODEL", None) is None
|
46
|
+
):
|
47
|
+
raise TypeError(
|
48
|
+
f"Class {cls.__name__} must define a class attribute 'DEFAULT_MODEL' (non-empty str)"
|
49
|
+
)
|
50
|
+
|
51
|
+
def fill_missing_device_info(self, config):
|
52
|
+
"""
|
53
|
+
Fill missing LLMDriverConfig fields (max_tokens, temperature, etc) from MODEL_SPECS for the chosen model.
|
54
|
+
Mutates the config in place.
|
55
|
+
"""
|
56
|
+
if not hasattr(self, "MODEL_SPECS"):
|
57
|
+
return
|
58
|
+
model_name = getattr(config, "model", None) or getattr(
|
59
|
+
self, "DEFAULT_MODEL", None
|
60
|
+
)
|
61
|
+
model_info = self.MODEL_SPECS.get(model_name)
|
62
|
+
if not model_info:
|
63
|
+
return
|
64
|
+
# Handle common fields from model_info
|
65
|
+
spec_dict = (
|
66
|
+
model_info.to_dict() if hasattr(model_info, "to_dict") else dict(model_info)
|
67
|
+
)
|
68
|
+
if (
|
69
|
+
hasattr(config, "max_tokens")
|
70
|
+
and getattr(config, "max_tokens", None) is None
|
71
|
+
):
|
72
|
+
val = spec_dict.get("max_tokens") or spec_dict.get("max_response")
|
73
|
+
if val is not None:
|
74
|
+
try:
|
75
|
+
config.max_tokens = int(val)
|
76
|
+
except Exception:
|
77
|
+
pass
|
78
|
+
if (
|
79
|
+
hasattr(config, "temperature")
|
80
|
+
and getattr(config, "temperature", None) is None
|
81
|
+
):
|
82
|
+
val = spec_dict.get("temperature")
|
83
|
+
if val is None:
|
84
|
+
val = spec_dict.get("default_temp")
|
85
|
+
if val is not None:
|
86
|
+
try:
|
87
|
+
config.temperature = float(val)
|
88
|
+
except Exception:
|
89
|
+
pass
|
90
|
+
|
91
|
+
@property
|
92
|
+
@abstractmethod
|
93
|
+
def driver(self) -> LLMDriver:
|
94
|
+
pass
|
95
|
+
|
96
|
+
def is_model_available(self, model_name):
|
97
|
+
"""
|
98
|
+
Returns True if the given model is available for this provider.
|
99
|
+
Default implementation checks MODEL_SPECS; override for dynamic providers.
|
100
|
+
"""
|
101
|
+
if not hasattr(self, "MODEL_SPECS"):
|
102
|
+
return False
|
103
|
+
return model_name in self.MODEL_SPECS
|
104
|
+
|
105
|
+
def get_model_info(self, model_name=None):
|
106
|
+
"""
|
107
|
+
Return the info dict for a given model (driver, params, etc). If model_name is None, return all model info dicts.
|
108
|
+
MODEL_SPECS must be dict[str, LLMModelInfo].
|
109
|
+
"""
|
110
|
+
if not hasattr(self, "MODEL_SPECS"):
|
111
|
+
raise NotImplementedError(
|
112
|
+
"This provider does not have a MODEL_SPECS attribute."
|
113
|
+
)
|
114
|
+
if model_name is None:
|
115
|
+
return {
|
116
|
+
name: model_info.to_dict()
|
117
|
+
for name, model_info in self.MODEL_SPECS.items()
|
118
|
+
}
|
119
|
+
if model_name in self.MODEL_SPECS:
|
120
|
+
return self.MODEL_SPECS[model_name].to_dict()
|
121
|
+
return None
|
122
|
+
|
123
|
+
def _validate_model_specs(self):
|
124
|
+
if not hasattr(self, "MODEL_SPECS"):
|
125
|
+
raise NotImplementedError(
|
126
|
+
"This provider does not have a MODEL_SPECS attribute."
|
127
|
+
)
|
128
|
+
|
129
|
+
def _get_model_name_from_config(self, config):
|
130
|
+
return (config or {}).get("model_name", getattr(self, "DEFAULT_MODEL", None))
|
131
|
+
|
132
|
+
def _get_model_spec_entry(self, model_name):
|
133
|
+
spec = self.MODEL_SPECS.get(model_name, None)
|
134
|
+
if spec is None:
|
135
|
+
raise ValueError(f"Model '{model_name}' not found in MODEL_SPECS.")
|
136
|
+
return spec
|
137
|
+
|
138
|
+
def _get_driver_name_from_spec(self, spec):
|
139
|
+
driver_name = None
|
140
|
+
if hasattr(spec, "driver") and spec.driver:
|
141
|
+
driver_name = spec.driver
|
142
|
+
elif hasattr(spec, "other") and isinstance(spec.other, dict):
|
143
|
+
driver_name = spec.other.get("driver", None)
|
144
|
+
return driver_name
|
145
|
+
|
146
|
+
def _resolve_driver_class(self, driver_name):
|
147
|
+
if not driver_name:
|
148
|
+
raise NotImplementedError(
|
149
|
+
"No driver class found or specified for this MODEL_SPECS entry."
|
150
|
+
)
|
151
|
+
module_root = "janito.drivers"
|
152
|
+
probable_path = None
|
153
|
+
mapping = {
|
154
|
+
"OpenAIResponsesModelDriver": "openai_responses.driver",
|
155
|
+
"OpenAIModelDriver": "openai.driver",
|
156
|
+
"AzureOpenAIModelDriver": "azure_openai.driver",
|
157
|
+
"GoogleGenaiModelDriver": "google_genai.driver",
|
158
|
+
}
|
159
|
+
if driver_name in mapping:
|
160
|
+
probable_path = mapping[driver_name]
|
161
|
+
module_path = f"{module_root}.{probable_path}"
|
162
|
+
mod = importlib.import_module(module_path)
|
163
|
+
return getattr(mod, driver_name)
|
164
|
+
# Attempt dynamic fallback based on convention
|
165
|
+
if driver_name.endswith("ModelDriver"):
|
166
|
+
base = driver_name[: -len("ModelDriver")]
|
167
|
+
mod_name = base.replace("_", "").lower()
|
168
|
+
module_path = f"{module_root}.{mod_name}.driver"
|
169
|
+
try:
|
170
|
+
mod = importlib.import_module(module_path)
|
171
|
+
return getattr(mod, driver_name)
|
172
|
+
except Exception:
|
173
|
+
pass
|
174
|
+
raise NotImplementedError(
|
175
|
+
"No driver class found for driver_name: {}".format(driver_name)
|
176
|
+
)
|
177
|
+
|
178
|
+
def _validate_required_config(self, driver_class, config, driver_name):
|
179
|
+
required = getattr(driver_class, "required_config", None)
|
180
|
+
if required:
|
181
|
+
missing = [
|
182
|
+
k
|
183
|
+
for k in required
|
184
|
+
if not config or k not in config or config.get(k) in (None, "")
|
185
|
+
]
|
186
|
+
if missing:
|
187
|
+
raise ValueError(
|
188
|
+
f"Missing required config for {driver_name}: {', '.join(missing)}"
|
189
|
+
)
|
190
|
+
|
191
|
+
def create_agent(self, tools_adapter=None, agent_name: str = None, **kwargs):
|
192
|
+
from janito.llm.agent import LLMAgent
|
193
|
+
|
194
|
+
# Dynamically create driver if supported, else fallback to existing.
|
195
|
+
driver = self.driver
|
196
|
+
return LLMAgent(self, tools_adapter, agent_name=agent_name, **kwargs)
|