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.
Files changed (93) hide show
  1. janito/__init__.py +6 -6
  2. janito/cli/chat_mode/shell/autocomplete.py +21 -21
  3. janito/cli/chat_mode/shell/commands/clear.py +12 -12
  4. janito/cli/chat_mode/shell/commands/multi.py +51 -51
  5. janito/cli/chat_mode/shell/input_history.py +62 -62
  6. janito/cli/cli_commands/list_models.py +35 -35
  7. janito/cli/cli_commands/list_providers.py +9 -9
  8. janito/cli/cli_commands/list_tools.py +53 -53
  9. janito/cli/cli_commands/model_selection.py +50 -50
  10. janito/cli/cli_commands/model_utils.py +95 -95
  11. janito/cli/cli_commands/set_api_key.py +19 -19
  12. janito/cli/cli_commands/show_config.py +51 -51
  13. janito/cli/cli_commands/show_system_prompt.py +62 -62
  14. janito/cli/core/__init__.py +4 -4
  15. janito/cli/core/event_logger.py +59 -59
  16. janito/cli/core/getters.py +33 -33
  17. janito/cli/core/unsetters.py +54 -54
  18. janito/cli/single_shot_mode/__init__.py +6 -6
  19. janito/config.py +5 -5
  20. janito/config_manager.py +112 -112
  21. janito/drivers/anthropic/driver.py +113 -113
  22. janito/formatting_token.py +54 -54
  23. janito/i18n/__init__.py +35 -35
  24. janito/i18n/messages.py +23 -23
  25. janito/i18n/pt.py +47 -47
  26. janito/llm/__init__.py +5 -5
  27. janito/llm/agent.py +443 -443
  28. janito/llm/auth.py +63 -63
  29. janito/llm/driver_config_builder.py +34 -34
  30. janito/llm/driver_input.py +12 -12
  31. janito/llm/message_parts.py +60 -60
  32. janito/llm/model.py +38 -38
  33. janito/llm/provider.py +196 -196
  34. janito/provider_registry.py +176 -176
  35. janito/providers/anthropic/model_info.py +22 -22
  36. janito/providers/anthropic/provider.py +2 -0
  37. janito/providers/azure_openai/model_info.py +16 -16
  38. janito/providers/azure_openai/provider.py +3 -0
  39. janito/providers/deepseek/__init__.py +1 -1
  40. janito/providers/deepseek/model_info.py +16 -16
  41. janito/providers/deepseek/provider.py +94 -91
  42. janito/providers/google/provider.py +3 -0
  43. janito/providers/mistralai/provider.py +3 -0
  44. janito/providers/openai/provider.py +4 -0
  45. janito/tools/adapters/__init__.py +1 -1
  46. janito/tools/adapters/local/ask_user.py +102 -102
  47. janito/tools/adapters/local/copy_file.py +84 -84
  48. janito/tools/adapters/local/create_directory.py +69 -69
  49. janito/tools/adapters/local/create_file.py +82 -82
  50. janito/tools/adapters/local/fetch_url.py +97 -97
  51. janito/tools/adapters/local/find_files.py +138 -138
  52. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  53. janito/tools/adapters/local/get_file_outline/core.py +117 -117
  54. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
  55. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  56. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  57. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  58. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  59. janito/tools/adapters/local/python_code_run.py +166 -166
  60. janito/tools/adapters/local/python_command_run.py +164 -164
  61. janito/tools/adapters/local/python_file_run.py +163 -163
  62. janito/tools/adapters/local/run_bash_command.py +176 -176
  63. janito/tools/adapters/local/run_powershell_command.py +219 -219
  64. janito/tools/adapters/local/search_text/__init__.py +1 -1
  65. janito/tools/adapters/local/search_text/core.py +201 -201
  66. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  67. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  68. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  69. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  70. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  71. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  72. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  73. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  74. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  75. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  76. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  77. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  78. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  79. janito/tools/adapters/local/view_file.py +167 -167
  80. janito/tools/inspect_registry.py +17 -17
  81. janito/tools/tool_base.py +105 -105
  82. janito/tools/tool_events.py +58 -58
  83. janito/tools/tool_run_exception.py +12 -12
  84. janito/tools/tool_use_tracker.py +81 -81
  85. janito/tools/tool_utils.py +45 -45
  86. janito/tools/tools_schema.py +104 -104
  87. janito/version.py +4 -4
  88. {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/METADATA +390 -388
  89. {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/RECORD +93 -93
  90. {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/WHEEL +0 -0
  91. {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/entry_points.txt +0 -0
  92. {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/licenses/LICENSE +0 -0
  93. {janito-2.3.0.dist-info → janito-2.3.1.dist-info}/top_level.txt +0 -0
@@ -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
+ )