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
janito/llm/auth.py CHANGED
@@ -1,63 +1,63 @@
1
- """
2
- LLMAuthManager: Handles authentication credentials for LLM providers, persisted in ~/.janito/auth.json or a custom path.
3
- """
4
-
5
- import os
6
- import json
7
- from typing import Dict, Optional
8
-
9
-
10
- class LLMAuthManager:
11
- """
12
- Manages authentication tokens, API keys, or credentials for LLM providers.
13
- Persists credentials in ~/.janito/auth.json or a custom path.
14
- """
15
-
16
- def __init__(self, auth_file: Optional[str] = None):
17
- if auth_file is not None:
18
- self._auth_file = os.path.expanduser(auth_file)
19
- else:
20
- self._auth_file = os.path.expanduser("~/.janito/auth.json")
21
- self._credentials: Dict[str, str] = {}
22
- self._load_credentials()
23
-
24
- def _load_credentials(self):
25
- if os.path.exists(self._auth_file):
26
- try:
27
- with open(self._auth_file, "r") as f:
28
- self._credentials = json.load(f)
29
- except Exception:
30
- self._credentials = {}
31
- else:
32
- self._credentials = {}
33
-
34
- def _save_credentials(self):
35
- os.makedirs(os.path.dirname(self._auth_file), exist_ok=True)
36
- with open(self._auth_file, "w") as f:
37
- json.dump(self._credentials, f, indent=2)
38
- f.write("\n")
39
-
40
- def set_credentials(self, provider_name: str, credentials: str) -> None:
41
- """
42
- Store credentials for a given provider and persist to disk. Raises ValueError if provider is unknown.
43
- """
44
- from janito.providers.registry import LLMProviderRegistry
45
-
46
- if provider_name not in LLMProviderRegistry.list_providers():
47
- raise ValueError(f"Unknown provider: {provider_name}")
48
- self._credentials[provider_name] = credentials
49
- self._save_credentials()
50
-
51
- def get_credentials(self, provider_name: str) -> Optional[str]:
52
- """
53
- Retrieve credentials for a given provider.
54
- """
55
- return self._credentials.get(provider_name)
56
-
57
- def remove_credentials(self, provider_name: str) -> None:
58
- """
59
- Remove credentials for a given provider and update disk.
60
- """
61
- if provider_name in self._credentials:
62
- del self._credentials[provider_name]
63
- self._save_credentials()
1
+ """
2
+ LLMAuthManager: Handles authentication credentials for LLM providers, persisted in ~/.janito/auth.json or a custom path.
3
+ """
4
+
5
+ import os
6
+ import json
7
+ from typing import Dict, Optional
8
+
9
+
10
+ class LLMAuthManager:
11
+ """
12
+ Manages authentication tokens, API keys, or credentials for LLM providers.
13
+ Persists credentials in ~/.janito/auth.json or a custom path.
14
+ """
15
+
16
+ def __init__(self, auth_file: Optional[str] = None):
17
+ if auth_file is not None:
18
+ self._auth_file = os.path.expanduser(auth_file)
19
+ else:
20
+ self._auth_file = os.path.expanduser("~/.janito/auth.json")
21
+ self._credentials: Dict[str, str] = {}
22
+ self._load_credentials()
23
+
24
+ def _load_credentials(self):
25
+ if os.path.exists(self._auth_file):
26
+ try:
27
+ with open(self._auth_file, "r") as f:
28
+ self._credentials = json.load(f)
29
+ except Exception:
30
+ self._credentials = {}
31
+ else:
32
+ self._credentials = {}
33
+
34
+ def _save_credentials(self):
35
+ os.makedirs(os.path.dirname(self._auth_file), exist_ok=True)
36
+ with open(self._auth_file, "w") as f:
37
+ json.dump(self._credentials, f, indent=2)
38
+ f.write("\n")
39
+
40
+ def set_credentials(self, provider_name: str, credentials: str) -> None:
41
+ """
42
+ Store credentials for a given provider and persist to disk. Raises ValueError if provider is unknown.
43
+ """
44
+ from janito.providers.registry import LLMProviderRegistry
45
+
46
+ if provider_name not in LLMProviderRegistry.list_providers():
47
+ raise ValueError(f"Unknown provider: {provider_name}")
48
+ self._credentials[provider_name] = credentials
49
+ self._save_credentials()
50
+
51
+ def get_credentials(self, provider_name: str) -> Optional[str]:
52
+ """
53
+ Retrieve credentials for a given provider.
54
+ """
55
+ return self._credentials.get(provider_name)
56
+
57
+ def remove_credentials(self, provider_name: str) -> None:
58
+ """
59
+ Remove credentials for a given provider and update disk.
60
+ """
61
+ if provider_name in self._credentials:
62
+ del self._credentials[provider_name]
63
+ self._save_credentials()
@@ -1,34 +1,34 @@
1
- from typing import Type, Dict, Any
2
- from janito.llm.driver_config import LLMDriverConfig
3
-
4
-
5
- def build_llm_driver_config(
6
- config: Dict[str, Any], driver_class: Type
7
- ) -> LLMDriverConfig:
8
- """
9
- Build an LLMDriverConfig instance for the given driver class based on its declared driver_fields.
10
- Only fills fields missing from given config; does not overwrite fields already provided.
11
- Any config fields not in driver_fields or LLMDriverConfig fields go into .extra.
12
- """
13
- driver_fields = getattr(driver_class, "driver_fields", None)
14
- if driver_fields is None:
15
- driver_fields = set(LLMDriverConfig.__dataclass_fields__.keys()) - {
16
- "model",
17
- "extra",
18
- }
19
- base_info = {}
20
- extra = {}
21
- for k, v in (config or {}).items():
22
- if k in driver_fields and k in LLMDriverConfig.__dataclass_fields__:
23
- base_info[k] = v
24
- else:
25
- extra[k] = v
26
- # Only set missing fields, do NOT overwrite those from CLI/user
27
- for field in driver_fields:
28
- if field not in base_info and field in LLMDriverConfig.__dataclass_fields__:
29
- base_info[field] = (
30
- None # Optional: replace None with provider/driver default if wanted
31
- )
32
- return LLMDriverConfig(
33
- model=config.get("model") or config.get("model_name"), extra=extra, **base_info
34
- )
1
+ from typing import Type, Dict, Any
2
+ from janito.llm.driver_config import LLMDriverConfig
3
+
4
+
5
+ def build_llm_driver_config(
6
+ config: Dict[str, Any], driver_class: Type
7
+ ) -> LLMDriverConfig:
8
+ """
9
+ Build an LLMDriverConfig instance for the given driver class based on its declared driver_fields.
10
+ Only fills fields missing from given config; does not overwrite fields already provided.
11
+ Any config fields not in driver_fields or LLMDriverConfig fields go into .extra.
12
+ """
13
+ driver_fields = getattr(driver_class, "driver_fields", None)
14
+ if driver_fields is None:
15
+ driver_fields = set(LLMDriverConfig.__dataclass_fields__.keys()) - {
16
+ "model",
17
+ "extra",
18
+ }
19
+ base_info = {}
20
+ extra = {}
21
+ for k, v in (config or {}).items():
22
+ if k in driver_fields and k in LLMDriverConfig.__dataclass_fields__:
23
+ base_info[k] = v
24
+ else:
25
+ extra[k] = v
26
+ # Only set missing fields, do NOT overwrite those from CLI/user
27
+ for field in driver_fields:
28
+ if field not in base_info and field in LLMDriverConfig.__dataclass_fields__:
29
+ base_info[field] = (
30
+ None # Optional: replace None with provider/driver default if wanted
31
+ )
32
+ return LLMDriverConfig(
33
+ model=config.get("model") or config.get("model_name"), extra=extra, **base_info
34
+ )
@@ -1,12 +1,12 @@
1
- from dataclasses import dataclass, field
2
- from typing import Optional
3
- import threading
4
- from janito.llm.driver_config import LLMDriverConfig
5
- from janito.conversation_history import LLMConversationHistory
6
-
7
-
8
- @dataclass
9
- class DriverInput:
10
- config: LLMDriverConfig
11
- conversation_history: LLMConversationHistory
12
- cancel_event: Optional[threading.Event] = field(default=None)
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional
3
+ import threading
4
+ from janito.llm.driver_config import LLMDriverConfig
5
+ from janito.conversation_history import LLMConversationHistory
6
+
7
+
8
+ @dataclass
9
+ class DriverInput:
10
+ config: LLMDriverConfig
11
+ conversation_history: LLMConversationHistory
12
+ cancel_event: Optional[threading.Event] = field(default=None)
@@ -1,60 +1,60 @@
1
- import attr
2
-
3
-
4
- class MessagePart:
5
- """
6
- Base class for all driver message parts.
7
- """
8
-
9
- type: str
10
-
11
-
12
- @attr.s(auto_attribs=True, kw_only=True)
13
- class TextMessagePart(MessagePart):
14
- content: str = ""
15
-
16
-
17
- @attr.s(auto_attribs=True, kw_only=True)
18
- class InlineDataMessagePart(MessagePart):
19
- content: bytes = b""
20
-
21
-
22
- @attr.s(auto_attribs=True, kw_only=True)
23
- class FileDataMessagePart(MessagePart):
24
- content: str = ""
25
-
26
-
27
- @attr.s(auto_attribs=True, kw_only=True)
28
- class VideoMetadataMessagePart(MessagePart):
29
- content: dict = attr.Factory(dict)
30
-
31
-
32
- @attr.s(auto_attribs=True, kw_only=True)
33
- class CodeExecutionResultMessagePart(MessagePart):
34
- content: str = ""
35
- stdout: str = ""
36
- stderr: str = ""
37
-
38
-
39
- @attr.s(auto_attribs=True, kw_only=True)
40
- class ExecutableCodeMessagePart(MessagePart):
41
- content: str = ""
42
-
43
-
44
- @attr.s(auto_attribs=True, kw_only=True)
45
- class FunctionCallMessagePart(MessagePart):
46
- tool_call_id: str = ""
47
- function: object = (
48
- None # Should match OpenAI SDK structure (with arguments as JSON string)
49
- )
50
-
51
-
52
- @attr.s(auto_attribs=True, kw_only=True)
53
- class FunctionResponseMessagePart(MessagePart):
54
- name: str = ""
55
- content: dict = attr.Factory(dict)
56
-
57
-
58
- @attr.s(auto_attribs=True, kw_only=True)
59
- class ThoughtMessagePart(MessagePart):
60
- content: bool = False
1
+ import attr
2
+
3
+
4
+ class MessagePart:
5
+ """
6
+ Base class for all driver message parts.
7
+ """
8
+
9
+ type: str
10
+
11
+
12
+ @attr.s(auto_attribs=True, kw_only=True)
13
+ class TextMessagePart(MessagePart):
14
+ content: str = ""
15
+
16
+
17
+ @attr.s(auto_attribs=True, kw_only=True)
18
+ class InlineDataMessagePart(MessagePart):
19
+ content: bytes = b""
20
+
21
+
22
+ @attr.s(auto_attribs=True, kw_only=True)
23
+ class FileDataMessagePart(MessagePart):
24
+ content: str = ""
25
+
26
+
27
+ @attr.s(auto_attribs=True, kw_only=True)
28
+ class VideoMetadataMessagePart(MessagePart):
29
+ content: dict = attr.Factory(dict)
30
+
31
+
32
+ @attr.s(auto_attribs=True, kw_only=True)
33
+ class CodeExecutionResultMessagePart(MessagePart):
34
+ content: str = ""
35
+ stdout: str = ""
36
+ stderr: str = ""
37
+
38
+
39
+ @attr.s(auto_attribs=True, kw_only=True)
40
+ class ExecutableCodeMessagePart(MessagePart):
41
+ content: str = ""
42
+
43
+
44
+ @attr.s(auto_attribs=True, kw_only=True)
45
+ class FunctionCallMessagePart(MessagePart):
46
+ tool_call_id: str = ""
47
+ function: object = (
48
+ None # Should match OpenAI SDK structure (with arguments as JSON string)
49
+ )
50
+
51
+
52
+ @attr.s(auto_attribs=True, kw_only=True)
53
+ class FunctionResponseMessagePart(MessagePart):
54
+ name: str = ""
55
+ content: dict = attr.Factory(dict)
56
+
57
+
58
+ @attr.s(auto_attribs=True, kw_only=True)
59
+ class ThoughtMessagePart(MessagePart):
60
+ content: bool = False
janito/llm/model.py CHANGED
@@ -1,38 +1,38 @@
1
- from dataclasses import dataclass, field
2
- from typing import Any, Optional
3
-
4
-
5
- @dataclass
6
- class LLMModelInfo:
7
- name: str
8
- context: Any = "N/A"
9
- max_input: Any = "N/A"
10
- max_cot: Any = "N/A"
11
- max_response: Any = "N/A"
12
- thinking_supported: Any = "N/A"
13
- default_temp: float = 0.2
14
- open: Optional[Any] = None
15
- category: Optional[str] = None
16
- driver: Optional[str] = None
17
- # This enables arbitrary provider-specific metadata
18
- other: dict = field(default_factory=dict)
19
-
20
- def to_dict(self) -> dict:
21
- d = self.__dict__.copy()
22
- if not self.open:
23
- d.pop("open")
24
- if not self.category:
25
- d.pop("category")
26
- if not self.driver:
27
- d.pop("driver")
28
- if not self.other:
29
- d.pop("other")
30
- return d
31
-
32
- @staticmethod
33
- def get_model_info(model_specs):
34
- """
35
- Standard get_model_info implementation for all providers:
36
- returns a list of model info dicts, one per model in the given MODEL_SPECS dict.
37
- """
38
- return [m.to_dict() for m in model_specs.values()]
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, Optional
3
+
4
+
5
+ @dataclass
6
+ class LLMModelInfo:
7
+ name: str
8
+ context: Any = "N/A"
9
+ max_input: Any = "N/A"
10
+ max_cot: Any = "N/A"
11
+ max_response: Any = "N/A"
12
+ thinking_supported: Any = "N/A"
13
+ default_temp: float = 0.2
14
+ open: Optional[Any] = None
15
+ category: Optional[str] = None
16
+ driver: Optional[str] = None
17
+ # This enables arbitrary provider-specific metadata
18
+ other: dict = field(default_factory=dict)
19
+
20
+ def to_dict(self) -> dict:
21
+ d = self.__dict__.copy()
22
+ if not self.open:
23
+ d.pop("open")
24
+ if not self.category:
25
+ d.pop("category")
26
+ if not self.driver:
27
+ d.pop("driver")
28
+ if not self.other:
29
+ d.pop("other")
30
+ return d
31
+
32
+ @staticmethod
33
+ def get_model_info(model_specs):
34
+ """
35
+ Standard get_model_info implementation for all providers:
36
+ returns a list of model info dicts, one per model in the given MODEL_SPECS dict.
37
+ """
38
+ return [m.to_dict() for m in model_specs.values()]