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/cli/core/unsetters.py
CHANGED
@@ -1,54 +1,54 @@
|
|
1
|
-
from janito.config import config as global_config
|
2
|
-
|
3
|
-
|
4
|
-
def handle_unset(args):
|
5
|
-
unset_arg = getattr(args, "unset", None)
|
6
|
-
if not unset_arg:
|
7
|
-
return False
|
8
|
-
key = unset_arg.strip().replace("-", "_")
|
9
|
-
if "." in key:
|
10
|
-
# Provider or model-specific keys
|
11
|
-
parts = key.split(".")
|
12
|
-
if len(parts) == 2:
|
13
|
-
provider, subkey = parts
|
14
|
-
current_val = (
|
15
|
-
global_config.file_config.get("providers", {})
|
16
|
-
.get(provider, {})
|
17
|
-
.get(subkey)
|
18
|
-
)
|
19
|
-
if current_val is not None:
|
20
|
-
del global_config.file_config["providers"][provider][subkey]
|
21
|
-
global_config.save()
|
22
|
-
print(f"{key}={current_val} was removed.")
|
23
|
-
return True
|
24
|
-
elif len(parts) == 3:
|
25
|
-
provider, model, subkey = parts
|
26
|
-
model_conf = (
|
27
|
-
global_config.file_config.get("providers", {})
|
28
|
-
.get(provider, {})
|
29
|
-
.get("models", {})
|
30
|
-
.get(model, {})
|
31
|
-
)
|
32
|
-
current_val = model_conf.get(subkey)
|
33
|
-
if current_val is not None:
|
34
|
-
del global_config.file_config["providers"][provider]["models"][model][
|
35
|
-
subkey
|
36
|
-
]
|
37
|
-
global_config.save()
|
38
|
-
print(f"{key}={current_val} was removed.")
|
39
|
-
return True
|
40
|
-
else:
|
41
|
-
current_val = global_config.file_config.get(key)
|
42
|
-
if current_val is not None:
|
43
|
-
del global_config.file_config[key]
|
44
|
-
global_config.save()
|
45
|
-
print(f"{key}={current_val} was removed.")
|
46
|
-
return True
|
47
|
-
if "=" in unset_arg:
|
48
|
-
provided_key = unset_arg.split("=")[0].strip()
|
49
|
-
print(
|
50
|
-
f"Error: --unset expected a key, not key=value. Did you mean: --unset {provided_key}?"
|
51
|
-
)
|
52
|
-
else:
|
53
|
-
print(f"Error: no value set for {key} (cannot remove)")
|
54
|
-
return True
|
1
|
+
from janito.config import config as global_config
|
2
|
+
|
3
|
+
|
4
|
+
def handle_unset(args):
|
5
|
+
unset_arg = getattr(args, "unset", None)
|
6
|
+
if not unset_arg:
|
7
|
+
return False
|
8
|
+
key = unset_arg.strip().replace("-", "_")
|
9
|
+
if "." in key:
|
10
|
+
# Provider or model-specific keys
|
11
|
+
parts = key.split(".")
|
12
|
+
if len(parts) == 2:
|
13
|
+
provider, subkey = parts
|
14
|
+
current_val = (
|
15
|
+
global_config.file_config.get("providers", {})
|
16
|
+
.get(provider, {})
|
17
|
+
.get(subkey)
|
18
|
+
)
|
19
|
+
if current_val is not None:
|
20
|
+
del global_config.file_config["providers"][provider][subkey]
|
21
|
+
global_config.save()
|
22
|
+
print(f"{key}={current_val} was removed.")
|
23
|
+
return True
|
24
|
+
elif len(parts) == 3:
|
25
|
+
provider, model, subkey = parts
|
26
|
+
model_conf = (
|
27
|
+
global_config.file_config.get("providers", {})
|
28
|
+
.get(provider, {})
|
29
|
+
.get("models", {})
|
30
|
+
.get(model, {})
|
31
|
+
)
|
32
|
+
current_val = model_conf.get(subkey)
|
33
|
+
if current_val is not None:
|
34
|
+
del global_config.file_config["providers"][provider]["models"][model][
|
35
|
+
subkey
|
36
|
+
]
|
37
|
+
global_config.save()
|
38
|
+
print(f"{key}={current_val} was removed.")
|
39
|
+
return True
|
40
|
+
else:
|
41
|
+
current_val = global_config.file_config.get(key)
|
42
|
+
if current_val is not None:
|
43
|
+
del global_config.file_config[key]
|
44
|
+
global_config.save()
|
45
|
+
print(f"{key}={current_val} was removed.")
|
46
|
+
return True
|
47
|
+
if "=" in unset_arg:
|
48
|
+
provided_key = unset_arg.split("=")[0].strip()
|
49
|
+
print(
|
50
|
+
f"Error: --unset expected a key, not key=value. Did you mean: --unset {provided_key}?"
|
51
|
+
)
|
52
|
+
else:
|
53
|
+
print(f"Error: no value set for {key} (cannot remove)")
|
54
|
+
return True
|
@@ -1,6 +1,6 @@
|
|
1
|
-
# janito.cli.single_shot_mode package
|
2
|
-
from .handler import PromptHandler
|
3
|
-
|
4
|
-
__all__ = [
|
5
|
-
"PromptHandler",
|
6
|
-
]
|
1
|
+
# janito.cli.single_shot_mode package
|
2
|
+
from .handler import PromptHandler
|
3
|
+
|
4
|
+
__all__ = [
|
5
|
+
"PromptHandler",
|
6
|
+
]
|
janito/config.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Shared Janito ConfigManager singleton
|
2
|
-
from janito.config_manager import ConfigManager
|
3
|
-
|
4
|
-
# Only one global instance! Used by CLI, provider_config, others:
|
5
|
-
config = ConfigManager(config_path=None)
|
1
|
+
# Shared Janito ConfigManager singleton
|
2
|
+
from janito.config_manager import ConfigManager
|
3
|
+
|
4
|
+
# Only one global instance! Used by CLI, provider_config, others:
|
5
|
+
config = ConfigManager(config_path=None)
|
janito/config_manager.py
CHANGED
@@ -1,112 +1,112 @@
|
|
1
|
-
import json
|
2
|
-
from pathlib import Path
|
3
|
-
from threading import Lock
|
4
|
-
|
5
|
-
|
6
|
-
class ConfigManager:
|
7
|
-
"""
|
8
|
-
Unified configuration manager supporting:
|
9
|
-
- Defaults
|
10
|
-
- File-based configuration
|
11
|
-
- Runtime overrides (e.g., CLI args)
|
12
|
-
"""
|
13
|
-
|
14
|
-
_instance = None
|
15
|
-
_lock = Lock()
|
16
|
-
|
17
|
-
def __new__(cls, *args, **kwargs):
|
18
|
-
with cls._lock:
|
19
|
-
if not cls._instance:
|
20
|
-
cls._instance = super(ConfigManager, cls).__new__(cls)
|
21
|
-
return cls._instance
|
22
|
-
|
23
|
-
def __init__(self, config_path=None, defaults=None, runtime_overrides=None):
|
24
|
-
# Lazy single-init
|
25
|
-
if hasattr(self, "_initialized") and self._initialized:
|
26
|
-
return
|
27
|
-
self._initialized = True
|
28
|
-
|
29
|
-
self.config_path = Path(config_path or Path.home() / ".janito" / "config.json")
|
30
|
-
self.defaults = dict(defaults) if defaults else {}
|
31
|
-
self.file_config = {}
|
32
|
-
self.runtime_overrides = dict(runtime_overrides) if runtime_overrides else {}
|
33
|
-
self._load_file_config()
|
34
|
-
|
35
|
-
def _load_file_config(self):
|
36
|
-
if self.config_path.exists():
|
37
|
-
with open(self.config_path, "r", encoding="utf-8") as f:
|
38
|
-
try:
|
39
|
-
self.file_config = json.load(f)
|
40
|
-
except Exception:
|
41
|
-
self.file_config = {}
|
42
|
-
else:
|
43
|
-
self.file_config = {}
|
44
|
-
|
45
|
-
def save(self):
|
46
|
-
self.config_path.parent.mkdir(parents=True, exist_ok=True)
|
47
|
-
with open(self.config_path, "w", encoding="utf-8") as f:
|
48
|
-
json.dump(self.file_config, f, indent=2)
|
49
|
-
f.write("\n")
|
50
|
-
|
51
|
-
def get(self, key, default=None):
|
52
|
-
# Precedence: runtime_overrides > file_config > defaults
|
53
|
-
for layer in (self.runtime_overrides, self.file_config, self.defaults):
|
54
|
-
if key in layer and layer[key] is not None:
|
55
|
-
return layer[key]
|
56
|
-
return default
|
57
|
-
|
58
|
-
def runtime_set(self, key, value):
|
59
|
-
self.runtime_overrides[key] = value
|
60
|
-
|
61
|
-
def file_set(self, key, value):
|
62
|
-
# Always reload, update, and persist
|
63
|
-
self._load_file_config()
|
64
|
-
self.file_config[key] = value
|
65
|
-
with open(self.config_path, "w", encoding="utf-8") as f:
|
66
|
-
json.dump(self.file_config, f, indent=2)
|
67
|
-
f.write("\n")
|
68
|
-
|
69
|
-
def all(self, layered=False):
|
70
|
-
merged = dict(self.defaults)
|
71
|
-
merged.update(self.file_config)
|
72
|
-
merged.update(self.runtime_overrides)
|
73
|
-
if layered:
|
74
|
-
# Only file+runtime, i.e., what is saved to disk
|
75
|
-
d = dict(self.file_config)
|
76
|
-
d.update(self.runtime_overrides)
|
77
|
-
return d
|
78
|
-
return merged
|
79
|
-
|
80
|
-
# Namespaced provider/model config
|
81
|
-
def get_provider_config(self, provider, default=None):
|
82
|
-
providers = self.file_config.get("providers") or {}
|
83
|
-
return providers.get(provider) or (default or {})
|
84
|
-
|
85
|
-
def set_provider_config(self, provider, key, value):
|
86
|
-
if "providers" not in self.file_config:
|
87
|
-
self.file_config["providers"] = {}
|
88
|
-
if provider not in self.file_config["providers"]:
|
89
|
-
self.file_config["providers"][provider] = {}
|
90
|
-
self.file_config["providers"][provider][key] = value
|
91
|
-
|
92
|
-
def get_provider_model_config(self, provider, model, default=None):
|
93
|
-
return (
|
94
|
-
self.file_config.get("providers")
|
95
|
-
or {}.get(provider, {}).get("models", {}).get(model)
|
96
|
-
or (default or {})
|
97
|
-
)
|
98
|
-
|
99
|
-
def set_provider_model_config(self, provider, model, key, value):
|
100
|
-
if "providers" not in self.file_config:
|
101
|
-
self.file_config["providers"] = {}
|
102
|
-
if provider not in self.file_config["providers"]:
|
103
|
-
self.file_config["providers"][provider] = {}
|
104
|
-
if "models" not in self.file_config["providers"][provider]:
|
105
|
-
self.file_config["providers"][provider]["models"] = {}
|
106
|
-
if model not in self.file_config["providers"][provider]["models"]:
|
107
|
-
self.file_config["providers"][provider]["models"][model] = {}
|
108
|
-
self.file_config["providers"][provider]["models"][model][key] = value
|
109
|
-
|
110
|
-
# Support loading runtime overrides after init (e.g. after parsing CLI args)
|
111
|
-
def apply_runtime_overrides(self, overrides_dict):
|
112
|
-
self.runtime_overrides.update(overrides_dict)
|
1
|
+
import json
|
2
|
+
from pathlib import Path
|
3
|
+
from threading import Lock
|
4
|
+
|
5
|
+
|
6
|
+
class ConfigManager:
|
7
|
+
"""
|
8
|
+
Unified configuration manager supporting:
|
9
|
+
- Defaults
|
10
|
+
- File-based configuration
|
11
|
+
- Runtime overrides (e.g., CLI args)
|
12
|
+
"""
|
13
|
+
|
14
|
+
_instance = None
|
15
|
+
_lock = Lock()
|
16
|
+
|
17
|
+
def __new__(cls, *args, **kwargs):
|
18
|
+
with cls._lock:
|
19
|
+
if not cls._instance:
|
20
|
+
cls._instance = super(ConfigManager, cls).__new__(cls)
|
21
|
+
return cls._instance
|
22
|
+
|
23
|
+
def __init__(self, config_path=None, defaults=None, runtime_overrides=None):
|
24
|
+
# Lazy single-init
|
25
|
+
if hasattr(self, "_initialized") and self._initialized:
|
26
|
+
return
|
27
|
+
self._initialized = True
|
28
|
+
|
29
|
+
self.config_path = Path(config_path or Path.home() / ".janito" / "config.json")
|
30
|
+
self.defaults = dict(defaults) if defaults else {}
|
31
|
+
self.file_config = {}
|
32
|
+
self.runtime_overrides = dict(runtime_overrides) if runtime_overrides else {}
|
33
|
+
self._load_file_config()
|
34
|
+
|
35
|
+
def _load_file_config(self):
|
36
|
+
if self.config_path.exists():
|
37
|
+
with open(self.config_path, "r", encoding="utf-8") as f:
|
38
|
+
try:
|
39
|
+
self.file_config = json.load(f)
|
40
|
+
except Exception:
|
41
|
+
self.file_config = {}
|
42
|
+
else:
|
43
|
+
self.file_config = {}
|
44
|
+
|
45
|
+
def save(self):
|
46
|
+
self.config_path.parent.mkdir(parents=True, exist_ok=True)
|
47
|
+
with open(self.config_path, "w", encoding="utf-8") as f:
|
48
|
+
json.dump(self.file_config, f, indent=2)
|
49
|
+
f.write("\n")
|
50
|
+
|
51
|
+
def get(self, key, default=None):
|
52
|
+
# Precedence: runtime_overrides > file_config > defaults
|
53
|
+
for layer in (self.runtime_overrides, self.file_config, self.defaults):
|
54
|
+
if key in layer and layer[key] is not None:
|
55
|
+
return layer[key]
|
56
|
+
return default
|
57
|
+
|
58
|
+
def runtime_set(self, key, value):
|
59
|
+
self.runtime_overrides[key] = value
|
60
|
+
|
61
|
+
def file_set(self, key, value):
|
62
|
+
# Always reload, update, and persist
|
63
|
+
self._load_file_config()
|
64
|
+
self.file_config[key] = value
|
65
|
+
with open(self.config_path, "w", encoding="utf-8") as f:
|
66
|
+
json.dump(self.file_config, f, indent=2)
|
67
|
+
f.write("\n")
|
68
|
+
|
69
|
+
def all(self, layered=False):
|
70
|
+
merged = dict(self.defaults)
|
71
|
+
merged.update(self.file_config)
|
72
|
+
merged.update(self.runtime_overrides)
|
73
|
+
if layered:
|
74
|
+
# Only file+runtime, i.e., what is saved to disk
|
75
|
+
d = dict(self.file_config)
|
76
|
+
d.update(self.runtime_overrides)
|
77
|
+
return d
|
78
|
+
return merged
|
79
|
+
|
80
|
+
# Namespaced provider/model config
|
81
|
+
def get_provider_config(self, provider, default=None):
|
82
|
+
providers = self.file_config.get("providers") or {}
|
83
|
+
return providers.get(provider) or (default or {})
|
84
|
+
|
85
|
+
def set_provider_config(self, provider, key, value):
|
86
|
+
if "providers" not in self.file_config:
|
87
|
+
self.file_config["providers"] = {}
|
88
|
+
if provider not in self.file_config["providers"]:
|
89
|
+
self.file_config["providers"][provider] = {}
|
90
|
+
self.file_config["providers"][provider][key] = value
|
91
|
+
|
92
|
+
def get_provider_model_config(self, provider, model, default=None):
|
93
|
+
return (
|
94
|
+
self.file_config.get("providers")
|
95
|
+
or {}.get(provider, {}).get("models", {}).get(model)
|
96
|
+
or (default or {})
|
97
|
+
)
|
98
|
+
|
99
|
+
def set_provider_model_config(self, provider, model, key, value):
|
100
|
+
if "providers" not in self.file_config:
|
101
|
+
self.file_config["providers"] = {}
|
102
|
+
if provider not in self.file_config["providers"]:
|
103
|
+
self.file_config["providers"][provider] = {}
|
104
|
+
if "models" not in self.file_config["providers"][provider]:
|
105
|
+
self.file_config["providers"][provider]["models"] = {}
|
106
|
+
if model not in self.file_config["providers"][provider]["models"]:
|
107
|
+
self.file_config["providers"][provider]["models"][model] = {}
|
108
|
+
self.file_config["providers"][provider]["models"][model][key] = value
|
109
|
+
|
110
|
+
# Support loading runtime overrides after init (e.g. after parsing CLI args)
|
111
|
+
def apply_runtime_overrides(self, overrides_dict):
|
112
|
+
self.runtime_overrides.update(overrides_dict)
|
@@ -1,113 +1,113 @@
|
|
1
|
-
from janito.llm.driver import LLMDriver
|
2
|
-
from janito.llm.driver_config import LLMDriverConfig
|
3
|
-
from janito.driver_events import (
|
4
|
-
GenerationStarted,
|
5
|
-
GenerationFinished,
|
6
|
-
RequestStarted,
|
7
|
-
RequestFinished,
|
8
|
-
ResponseReceived,
|
9
|
-
)
|
10
|
-
from janito.llm.message_parts import TextMessagePart
|
11
|
-
import uuid
|
12
|
-
import traceback
|
13
|
-
import time
|
14
|
-
|
15
|
-
# Safe import of anthropic SDK
|
16
|
-
try:
|
17
|
-
import anthropic
|
18
|
-
|
19
|
-
DRIVER_AVAILABLE = True
|
20
|
-
DRIVER_UNAVAILABLE_REASON = None
|
21
|
-
except ImportError:
|
22
|
-
DRIVER_AVAILABLE = False
|
23
|
-
DRIVER_UNAVAILABLE_REASON = "Missing dependency: anthropic (pip install anthropic)"
|
24
|
-
|
25
|
-
|
26
|
-
class AnthropicModelDriver(LLMDriver):
|
27
|
-
available = False
|
28
|
-
unavailable_reason = "AnthropicModelDriver is not implemented yet."
|
29
|
-
|
30
|
-
@classmethod
|
31
|
-
def is_available(cls):
|
32
|
-
return cls.available
|
33
|
-
|
34
|
-
"""
|
35
|
-
LLMDriver for Anthropic's Claude API (v3), using the anthropic SDK.
|
36
|
-
"""
|
37
|
-
required_config = ["api_key", "model"]
|
38
|
-
|
39
|
-
def __init__(self, tools_adapter=None):
|
40
|
-
raise ImportError(self.unavailable_reason)
|
41
|
-
|
42
|
-
def _create_client(self):
|
43
|
-
try:
|
44
|
-
import anthropic
|
45
|
-
except ImportError:
|
46
|
-
raise Exception(
|
47
|
-
"The 'anthropic' Python SDK is required. Please install via `pip install anthropic`."
|
48
|
-
)
|
49
|
-
return anthropic.Anthropic(api_key=self.api_key)
|
50
|
-
|
51
|
-
def _run_generation(
|
52
|
-
self, messages_or_prompt, system_prompt=None, tools=None, **kwargs
|
53
|
-
):
|
54
|
-
request_id = str(uuid.uuid4())
|
55
|
-
client = self._create_client()
|
56
|
-
try:
|
57
|
-
prompt = ""
|
58
|
-
if isinstance(messages_or_prompt, str):
|
59
|
-
prompt = messages_or_prompt
|
60
|
-
elif isinstance(messages_or_prompt, list):
|
61
|
-
chat = []
|
62
|
-
for msg in messages_or_prompt:
|
63
|
-
if msg.get("role") == "user":
|
64
|
-
chat.append("Human: " + msg.get("content", ""))
|
65
|
-
elif msg.get("role") == "assistant":
|
66
|
-
chat.append("Assistant: " + msg.get("content", ""))
|
67
|
-
prompt = "\n".join(chat)
|
68
|
-
if system_prompt:
|
69
|
-
prompt = f"System: {system_prompt}\n{prompt}"
|
70
|
-
|
71
|
-
self.publish(
|
72
|
-
GenerationStarted,
|
73
|
-
request_id,
|
74
|
-
conversation_history=list(getattr(self, "_history", [])),
|
75
|
-
)
|
76
|
-
self.publish(RequestStarted, request_id, payload={})
|
77
|
-
start_time = time.time()
|
78
|
-
response = client.completions.create(
|
79
|
-
model=self.model_name,
|
80
|
-
max_tokens_to_sample=int(getattr(self.config, "max_response", 1024)),
|
81
|
-
prompt=prompt,
|
82
|
-
temperature=float(getattr(self.config, "default_temp", 0.7)),
|
83
|
-
)
|
84
|
-
duration = time.time() - start_time
|
85
|
-
content = response.completion if hasattr(response, "completion") else None
|
86
|
-
self.publish(
|
87
|
-
RequestFinished,
|
88
|
-
request_id,
|
89
|
-
response=content,
|
90
|
-
status=RequestStatus.SUCCESS,
|
91
|
-
usage={},
|
92
|
-
)
|
93
|
-
parts = []
|
94
|
-
if content:
|
95
|
-
parts.append(TextMessagePart(content=content))
|
96
|
-
self.publish(
|
97
|
-
ResponseReceived,
|
98
|
-
request_id=request_id,
|
99
|
-
parts=parts,
|
100
|
-
tool_results=[],
|
101
|
-
timestamp=time.time(),
|
102
|
-
metadata={"raw_response": response},
|
103
|
-
)
|
104
|
-
self.publish(GenerationFinished, request_id, total_turns=1)
|
105
|
-
except Exception as e:
|
106
|
-
self.publish(
|
107
|
-
RequestFinished,
|
108
|
-
request_id,
|
109
|
-
status=RequestStatus.ERROR,
|
110
|
-
error=str(e),
|
111
|
-
exception=e,
|
112
|
-
traceback=traceback.format_exc(),
|
113
|
-
)
|
1
|
+
from janito.llm.driver import LLMDriver
|
2
|
+
from janito.llm.driver_config import LLMDriverConfig
|
3
|
+
from janito.driver_events import (
|
4
|
+
GenerationStarted,
|
5
|
+
GenerationFinished,
|
6
|
+
RequestStarted,
|
7
|
+
RequestFinished,
|
8
|
+
ResponseReceived,
|
9
|
+
)
|
10
|
+
from janito.llm.message_parts import TextMessagePart
|
11
|
+
import uuid
|
12
|
+
import traceback
|
13
|
+
import time
|
14
|
+
|
15
|
+
# Safe import of anthropic SDK
|
16
|
+
try:
|
17
|
+
import anthropic
|
18
|
+
|
19
|
+
DRIVER_AVAILABLE = True
|
20
|
+
DRIVER_UNAVAILABLE_REASON = None
|
21
|
+
except ImportError:
|
22
|
+
DRIVER_AVAILABLE = False
|
23
|
+
DRIVER_UNAVAILABLE_REASON = "Missing dependency: anthropic (pip install anthropic)"
|
24
|
+
|
25
|
+
|
26
|
+
class AnthropicModelDriver(LLMDriver):
|
27
|
+
available = False
|
28
|
+
unavailable_reason = "AnthropicModelDriver is not implemented yet."
|
29
|
+
|
30
|
+
@classmethod
|
31
|
+
def is_available(cls):
|
32
|
+
return cls.available
|
33
|
+
|
34
|
+
"""
|
35
|
+
LLMDriver for Anthropic's Claude API (v3), using the anthropic SDK.
|
36
|
+
"""
|
37
|
+
required_config = ["api_key", "model"]
|
38
|
+
|
39
|
+
def __init__(self, tools_adapter=None):
|
40
|
+
raise ImportError(self.unavailable_reason)
|
41
|
+
|
42
|
+
def _create_client(self):
|
43
|
+
try:
|
44
|
+
import anthropic
|
45
|
+
except ImportError:
|
46
|
+
raise Exception(
|
47
|
+
"The 'anthropic' Python SDK is required. Please install via `pip install anthropic`."
|
48
|
+
)
|
49
|
+
return anthropic.Anthropic(api_key=self.api_key)
|
50
|
+
|
51
|
+
def _run_generation(
|
52
|
+
self, messages_or_prompt, system_prompt=None, tools=None, **kwargs
|
53
|
+
):
|
54
|
+
request_id = str(uuid.uuid4())
|
55
|
+
client = self._create_client()
|
56
|
+
try:
|
57
|
+
prompt = ""
|
58
|
+
if isinstance(messages_or_prompt, str):
|
59
|
+
prompt = messages_or_prompt
|
60
|
+
elif isinstance(messages_or_prompt, list):
|
61
|
+
chat = []
|
62
|
+
for msg in messages_or_prompt:
|
63
|
+
if msg.get("role") == "user":
|
64
|
+
chat.append("Human: " + msg.get("content", ""))
|
65
|
+
elif msg.get("role") == "assistant":
|
66
|
+
chat.append("Assistant: " + msg.get("content", ""))
|
67
|
+
prompt = "\n".join(chat)
|
68
|
+
if system_prompt:
|
69
|
+
prompt = f"System: {system_prompt}\n{prompt}"
|
70
|
+
|
71
|
+
self.publish(
|
72
|
+
GenerationStarted,
|
73
|
+
request_id,
|
74
|
+
conversation_history=list(getattr(self, "_history", [])),
|
75
|
+
)
|
76
|
+
self.publish(RequestStarted, request_id, payload={})
|
77
|
+
start_time = time.time()
|
78
|
+
response = client.completions.create(
|
79
|
+
model=self.model_name,
|
80
|
+
max_tokens_to_sample=int(getattr(self.config, "max_response", 1024)),
|
81
|
+
prompt=prompt,
|
82
|
+
temperature=float(getattr(self.config, "default_temp", 0.7)),
|
83
|
+
)
|
84
|
+
duration = time.time() - start_time
|
85
|
+
content = response.completion if hasattr(response, "completion") else None
|
86
|
+
self.publish(
|
87
|
+
RequestFinished,
|
88
|
+
request_id,
|
89
|
+
response=content,
|
90
|
+
status=RequestStatus.SUCCESS,
|
91
|
+
usage={},
|
92
|
+
)
|
93
|
+
parts = []
|
94
|
+
if content:
|
95
|
+
parts.append(TextMessagePart(content=content))
|
96
|
+
self.publish(
|
97
|
+
ResponseReceived,
|
98
|
+
request_id=request_id,
|
99
|
+
parts=parts,
|
100
|
+
tool_results=[],
|
101
|
+
timestamp=time.time(),
|
102
|
+
metadata={"raw_response": response},
|
103
|
+
)
|
104
|
+
self.publish(GenerationFinished, request_id, total_turns=1)
|
105
|
+
except Exception as e:
|
106
|
+
self.publish(
|
107
|
+
RequestFinished,
|
108
|
+
request_id,
|
109
|
+
status=RequestStatus.ERROR,
|
110
|
+
error=str(e),
|
111
|
+
exception=e,
|
112
|
+
traceback=traceback.format_exc(),
|
113
|
+
)
|