janito 2.3.0__py3-none-any.whl → 2.4.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.
Files changed (150) hide show
  1. janito/__init__.py +6 -6
  2. janito/_version.py +57 -0
  3. janito/agent/setup_agent.py +92 -18
  4. janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +44 -0
  5. janito/cli/chat_mode/bindings.py +21 -2
  6. janito/cli/chat_mode/chat_entry.py +2 -3
  7. janito/cli/chat_mode/prompt_style.py +5 -0
  8. janito/cli/chat_mode/session.py +80 -94
  9. janito/cli/chat_mode/session_profile_select.py +80 -0
  10. janito/cli/chat_mode/shell/autocomplete.py +21 -21
  11. janito/cli/chat_mode/shell/commands/__init__.py +13 -7
  12. janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
  13. janito/cli/chat_mode/shell/commands/clear.py +12 -12
  14. janito/cli/chat_mode/shell/commands/conversation_restart.py +30 -0
  15. janito/cli/chat_mode/shell/commands/execute.py +42 -0
  16. janito/cli/chat_mode/shell/commands/help.py +6 -3
  17. janito/cli/chat_mode/shell/commands/model.py +28 -0
  18. janito/cli/chat_mode/shell/commands/multi.py +51 -51
  19. janito/cli/chat_mode/shell/commands/read.py +37 -0
  20. janito/cli/chat_mode/shell/commands/tools.py +45 -18
  21. janito/cli/chat_mode/shell/commands/write.py +37 -0
  22. janito/cli/chat_mode/shell/commands.bak.zip +0 -0
  23. janito/cli/chat_mode/shell/input_history.py +62 -62
  24. janito/cli/chat_mode/shell/session.bak.zip +0 -0
  25. janito/cli/chat_mode/toolbar.py +44 -27
  26. janito/cli/cli_commands/list_models.py +35 -35
  27. janito/cli/cli_commands/list_providers.py +9 -9
  28. janito/cli/cli_commands/list_tools.py +86 -53
  29. janito/cli/cli_commands/model_selection.py +50 -50
  30. janito/cli/cli_commands/set_api_key.py +19 -19
  31. janito/cli/cli_commands/show_config.py +51 -51
  32. janito/cli/cli_commands/show_system_prompt.py +105 -62
  33. janito/cli/config.py +5 -6
  34. janito/cli/core/__init__.py +4 -4
  35. janito/cli/core/event_logger.py +59 -59
  36. janito/cli/core/runner.py +25 -18
  37. janito/cli/core/setters.py +10 -1
  38. janito/cli/core/unsetters.py +54 -54
  39. janito/cli/main_cli.py +28 -5
  40. janito/cli/prompt_core.py +18 -2
  41. janito/cli/prompt_setup.py +56 -0
  42. janito/cli/single_shot_mode/__init__.py +6 -6
  43. janito/cli/single_shot_mode/handler.py +14 -73
  44. janito/cli/verbose_output.py +1 -1
  45. janito/config.py +5 -5
  46. janito/config_manager.py +13 -0
  47. janito/drivers/anthropic/driver.py +113 -113
  48. janito/drivers/dashscope.bak.zip +0 -0
  49. janito/drivers/openai/README.md +20 -0
  50. janito/drivers/openai_responses.bak.zip +0 -0
  51. janito/event_bus/event.py +2 -2
  52. janito/formatting_token.py +54 -54
  53. janito/i18n/__init__.py +35 -35
  54. janito/i18n/messages.py +23 -23
  55. janito/i18n/pt.py +46 -47
  56. janito/llm/README.md +23 -0
  57. janito/llm/__init__.py +5 -5
  58. janito/llm/agent.py +507 -443
  59. janito/llm/driver.py +8 -0
  60. janito/llm/driver_config_builder.py +34 -34
  61. janito/llm/driver_input.py +12 -12
  62. janito/llm/message_parts.py +60 -60
  63. janito/llm/model.py +38 -38
  64. janito/llm/provider.py +196 -196
  65. janito/provider_registry.py +8 -6
  66. janito/providers/anthropic/model_info.py +22 -22
  67. janito/providers/anthropic/provider.py +2 -0
  68. janito/providers/azure_openai/provider.py +3 -0
  69. janito/providers/dashscope.bak.zip +0 -0
  70. janito/providers/deepseek/__init__.py +1 -1
  71. janito/providers/deepseek/model_info.py +16 -16
  72. janito/providers/deepseek/provider.py +94 -91
  73. janito/providers/google/provider.py +3 -0
  74. janito/providers/mistralai/provider.py +3 -0
  75. janito/providers/openai/provider.py +4 -0
  76. janito/providers/registry.py +26 -26
  77. janito/shell.bak.zip +0 -0
  78. janito/tools/DOCSTRING_STANDARD.txt +33 -0
  79. janito/tools/README.md +3 -0
  80. janito/tools/__init__.py +20 -6
  81. janito/tools/adapters/__init__.py +1 -1
  82. janito/tools/adapters/local/__init__.py +65 -62
  83. janito/tools/adapters/local/adapter.py +18 -35
  84. janito/tools/adapters/local/ask_user.py +101 -102
  85. janito/tools/adapters/local/copy_file.py +84 -84
  86. janito/tools/adapters/local/create_directory.py +69 -69
  87. janito/tools/adapters/local/create_file.py +82 -82
  88. janito/tools/adapters/local/delete_text_in_file.py +2 -2
  89. janito/tools/adapters/local/fetch_url.py +97 -97
  90. janito/tools/adapters/local/find_files.py +139 -138
  91. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  92. janito/tools/adapters/local/get_file_outline/core.py +117 -117
  93. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
  94. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  95. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  96. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  97. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  98. janito/tools/adapters/local/move_file.py +2 -2
  99. janito/tools/adapters/local/open_html_in_browser.py +2 -1
  100. janito/tools/adapters/local/open_url.py +2 -2
  101. janito/tools/adapters/local/python_code_run.py +166 -166
  102. janito/tools/adapters/local/python_command_run.py +164 -164
  103. janito/tools/adapters/local/python_file_run.py +163 -163
  104. janito/tools/adapters/local/remove_directory.py +2 -2
  105. janito/tools/adapters/local/remove_file.py +2 -2
  106. janito/tools/adapters/local/replace_text_in_file.py +2 -2
  107. janito/tools/adapters/local/run_bash_command.py +176 -176
  108. janito/tools/adapters/local/run_powershell_command.py +219 -219
  109. janito/tools/adapters/local/search_text/__init__.py +1 -1
  110. janito/tools/adapters/local/search_text/core.py +201 -201
  111. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  112. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  113. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  114. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  115. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  116. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  117. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  118. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  119. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  120. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  121. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  122. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  123. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  124. janito/tools/adapters/local/view_file.py +168 -167
  125. janito/tools/inspect_registry.py +17 -17
  126. janito/tools/outline_file.bak.zip +0 -0
  127. janito/tools/permissions.py +45 -0
  128. janito/tools/permissions_parse.py +12 -0
  129. janito/tools/tool_base.py +118 -105
  130. janito/tools/tool_events.py +58 -58
  131. janito/tools/tool_run_exception.py +12 -12
  132. janito/tools/tool_use_tracker.py +81 -81
  133. janito/tools/tool_utils.py +43 -45
  134. janito/tools/tools_adapter.py +25 -20
  135. janito/tools/tools_schema.py +104 -104
  136. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/METADATA +425 -388
  137. janito-2.4.0.dist-info/RECORD +195 -0
  138. janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +0 -13
  139. janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +0 -37
  140. janito/cli/chat_mode/shell/commands/edit.py +0 -25
  141. janito/cli/chat_mode/shell/commands/exec.py +0 -27
  142. janito/cli/chat_mode/shell/commands/termweb_log.py +0 -92
  143. janito/cli/termweb_starter.py +0 -122
  144. janito/termweb/app.py +0 -95
  145. janito/version.py +0 -4
  146. janito-2.3.0.dist-info/RECORD +0 -181
  147. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/WHEEL +0 -0
  148. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/entry_points.txt +0 -0
  149. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/licenses/LICENSE +0 -0
  150. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/top_level.txt +0 -0
janito/cli/main_cli.py CHANGED
@@ -14,6 +14,14 @@ from janito.cli.core.event_logger import (
14
14
  )
15
15
 
16
16
  definition = [
17
+ (
18
+ ["--profile"],
19
+ {
20
+ "metavar": "PROFILE",
21
+ "help": "Select the profile name for the system prompt (e.g. 'developer').",
22
+ "default": None,
23
+ },
24
+ ),
17
25
  (
18
26
  ["-W", "--workdir"],
19
27
  {
@@ -57,6 +65,20 @@ definition = [
57
65
  "help": "Enable execution/run tools (allows running code or shell tools from the CLI)",
58
66
  },
59
67
  ),
68
+ (
69
+ ["-r", "--read"],
70
+ {
71
+ "action": "store_true",
72
+ "help": "Enable tools that require read permissions",
73
+ },
74
+ ),
75
+ (
76
+ ["-w", "--write"],
77
+ {
78
+ "action": "store_true",
79
+ "help": "Enable tools that require write permissions",
80
+ },
81
+ ),
60
82
  (["--unset"], {"metavar": "KEY", "help": "Unset (remove) a config key"}),
61
83
  (["--version"], {"action": "version", "version": None}),
62
84
  (["--list-tools"], {"action": "store_true", "help": "List all registered tools"}),
@@ -85,7 +107,6 @@ definition = [
85
107
  "help": "Show the resolved system prompt for the main agent",
86
108
  },
87
109
  ),
88
- (["-r", "--role"], {"metavar": "ROLE", "help": "Set the role for the agent"}),
89
110
  (["-p", "--provider"], {"metavar": "PROVIDER", "help": "Select the provider"}),
90
111
  (["-m", "--model"], {"metavar": "MODEL", "help": "Select the model"}),
91
112
  (
@@ -104,7 +125,7 @@ definition = [
104
125
  },
105
126
  ),
106
127
  (
107
- ["-w", "--web"],
128
+ ["--web"],
108
129
  {
109
130
  "action": "store_true",
110
131
  "default": False,
@@ -112,11 +133,11 @@ definition = [
112
133
  },
113
134
  ),
114
135
  (
115
- ["--termweb-port"],
136
+ ["---port"],
116
137
  {
117
138
  "type": int,
118
139
  "default": 8088,
119
- "help": "Port for the termweb server (default: 8088)",
140
+ "help": "Port for the server (default: 8088)",
120
141
  },
121
142
  ),
122
143
  (["--effort"],
@@ -150,10 +171,12 @@ MODIFIER_KEYS = [
150
171
  "verbose",
151
172
  "raw",
152
173
  "web",
153
- "termweb_port",
174
+ "_port",
154
175
  "verbose_api",
155
176
  "verbose_tools",
156
177
  "exec",
178
+ "read",
179
+ "write",
157
180
  ]
158
181
  SETTER_KEYS = ["set", "set_provider", "set_api_key", "unset"]
159
182
  GETTER_KEYS = ["show_config", "list_providers", "list_models", "list_tools"]
janito/cli/prompt_core.py CHANGED
@@ -3,7 +3,7 @@ Core PromptHandler: Handles prompt submission and response formatting for janito
3
3
  """
4
4
 
5
5
  import time
6
- from janito.version import __version__ as VERSION
6
+ from janito import __version__ as VERSION
7
7
  from janito.performance_collector import PerformanceCollector
8
8
  from rich.status import Status
9
9
  from rich.console import Console
@@ -210,7 +210,23 @@ class PromptHandler:
210
210
  on_event(final_event)
211
211
  global_event_bus.publish(final_event)
212
212
  except KeyboardInterrupt:
213
- self.console.print("[red]Request interrupted.[red]")
213
+ # Capture user interrupt / cancellation
214
+ self.console.print("[red]Interrupted by the user.[/red]")
215
+ try:
216
+ from janito.driver_events import RequestFinished, RequestStatus
217
+ # Record a synthetic "cancelled" final event so that downstream
218
+ # handlers (e.g. single_shot_mode.handler._post_prompt_actions)
219
+ # can reliably detect that the prompt was interrupted by the
220
+ # user and avoid showing misleading messages such as
221
+ # "No output produced by the model.".
222
+ if hasattr(self, "agent") and self.agent is not None:
223
+ self.agent.last_event = RequestFinished(
224
+ status=RequestStatus.CANCELLED,
225
+ reason="Interrupted by the user",
226
+ )
227
+ except Exception:
228
+ # Do not fail on cleanup – this hook is best-effort only.
229
+ pass
214
230
 
215
231
  def _print_verbose_debug(self, message):
216
232
  if hasattr(self.args, "verbose_agent") and self.args.verbose_agent:
@@ -0,0 +1,56 @@
1
+ """
2
+ Shared utilities to set up an agent together with a GenericPromptHandler that
3
+ both single–shot and chat modes can reuse. Having one central place avoids the
4
+ code duplication that previously existed in `chat_mode.session.ChatSession` and
5
+ `single_shot_mode.handler.PromptHandler`.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from janito.agent.setup_agent import create_configured_agent
10
+ from janito.cli.prompt_core import (
11
+ PromptHandler as GenericPromptHandler,
12
+ )
13
+ from typing import Any, Optional
14
+
15
+
16
+ def setup_agent_and_prompt_handler(
17
+ *,
18
+ args: Any,
19
+ provider_instance: Any,
20
+ llm_driver_config: Any,
21
+ role: Optional[str] = None,
22
+ verbose_tools: bool = False,
23
+ verbose_agent: bool = False,
24
+ exec_enabled: bool = False,
25
+ allowed_permissions: Optional[list[str]] = None,
26
+ profile: Optional[str] = None,
27
+ profile_system_prompt: Optional[str] = None,
28
+ conversation_history: Any = None,
29
+ ):
30
+ """Create a configured *agent* as well as a *GenericPromptHandler* bound to
31
+ that agent and return them as a tuple.
32
+
33
+ This helper consolidates the repetitive boiler-plate that was scattered
34
+ across *single-shot* and *chat* modes – both of which need an agent plus a
35
+ prompt handler that points to that agent.
36
+ """
37
+ agent = create_configured_agent(
38
+ provider_instance=provider_instance,
39
+ llm_driver_config=llm_driver_config,
40
+ role=role,
41
+ verbose_tools=verbose_tools,
42
+ verbose_agent=verbose_agent,
43
+ exec_enabled=exec_enabled,
44
+ allowed_permissions=allowed_permissions,
45
+ profile=profile,
46
+ profile_system_prompt=profile_system_prompt,
47
+ )
48
+
49
+ prompt_handler = GenericPromptHandler(
50
+ args=args,
51
+ conversation_history=conversation_history,
52
+ provider_instance=provider_instance,
53
+ )
54
+ prompt_handler.agent = agent
55
+
56
+ return agent, prompt_handler
@@ -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
+ ]
@@ -2,48 +2,32 @@
2
2
  PromptHandler: Handles prompt submission and response formatting for janito CLI (one-shot prompt execution).
3
3
  """
4
4
 
5
- import time
6
- from janito.version import __version__ as VERSION
7
- from janito.cli.prompt_core import PromptHandler as GenericPromptHandler
8
- from janito.cli.verbose_output import (
9
- print_verbose_header,
10
- print_performance,
11
- handle_exception,
12
- )
5
+ from __future__ import annotations
6
+
7
+ from janito.cli.prompt_setup import setup_agent_and_prompt_handler
13
8
  import janito.tools # Ensure all tools are registered
14
9
  from janito.cli.console import shared_console
15
10
 
16
11
 
17
12
  class PromptHandler:
18
- def __init__(self, args, provider_instance, llm_driver_config, role=None, exec_enabled=False):
13
+ def __init__(self, args, provider_instance, llm_driver_config, role=None, exec_enabled=False, allowed_permissions=None):
19
14
  self.args = args
20
15
  self.provider_instance = provider_instance
21
16
  self.llm_driver_config = llm_driver_config
22
17
  self.role = role
23
18
  self.exec_enabled = exec_enabled
24
- from janito.agent.setup_agent import create_configured_agent
25
-
26
- # DEBUG: Print exec_enabled propagation
27
- self.agent = create_configured_agent(
19
+ # Instantiate agent together with prompt handler using the shared helper
20
+ self.agent, self.generic_handler = setup_agent_and_prompt_handler(
21
+ args=args,
28
22
  provider_instance=provider_instance,
29
23
  llm_driver_config=llm_driver_config,
30
24
  role=role,
31
25
  verbose_tools=getattr(args, "verbose_tools", False),
32
26
  verbose_agent=getattr(args, "verbose_agent", False),
33
27
  exec_enabled=exec_enabled,
28
+ allowed_permissions=allowed_permissions,
29
+ profile=getattr(args, "profile", None),
34
30
  )
35
- # Setup conversation/history if needed
36
- # Dynamically enable/disable execution tools in the registry
37
- try:
38
- registry = __import__('janito.tools', fromlist=['get_local_tools_adapter']).get_local_tools_adapter()
39
- if hasattr(registry, 'set_execution_tools_enabled'):
40
- registry.set_execution_tools_enabled(exec_enabled)
41
- except Exception as e:
42
- shared_console.print(f"[yellow]Warning: Could not update execution tools dynamically in single-shot mode: {e}[/yellow]")
43
- self.generic_handler = GenericPromptHandler(
44
- args, [], provider_instance=provider_instance
45
- )
46
- self.generic_handler.agent = self.agent
47
31
 
48
32
  def handle(self) -> None:
49
33
  import traceback
@@ -75,56 +59,13 @@ class PromptHandler:
75
59
  self._post_prompt_actions()
76
60
 
77
61
  def _post_prompt_actions(self):
78
- final_event = getattr(self.agent, "last_event", None)
79
- if final_event is not None:
80
- self._print_exit_reason_and_parts(final_event)
81
- # --- BEGIN: Print token info in rich rule if --verbose is set ---
82
- if hasattr(self.args, "verbose") and self.args.verbose:
83
- from janito.perf_singleton import performance_collector
84
-
85
- token_info = performance_collector.get_last_request_usage()
86
- from rich.rule import Rule
87
- from rich import print as rich_print
88
- from janito.cli.utils import format_tokens
89
-
90
- if token_info:
91
- if isinstance(token_info, dict):
92
- token_str = " | ".join(
93
- f"{k}: {format_tokens(v) if isinstance(v, int) else v}"
94
- for k, v in token_info.items()
95
- )
96
- else:
97
- token_str = str(token_info)
98
- rich_print(Rule(f"[bold cyan]Token Usage[/bold cyan] {token_str}"))
99
- else:
100
- rich_print(Rule("[cyan]No token usage info available.[/cyan]"))
101
- else:
102
- shared_console.print("[yellow]No output produced by the model.[/yellow]")
62
+ # Align with chat mode: only print token usage summary
63
+ from janito.formatting_token import print_token_message_summary
64
+ from janito.perf_singleton import performance_collector
65
+ usage = performance_collector.get_last_request_usage()
66
+ print_token_message_summary(shared_console, msg_count=1, usage=usage)
103
67
  self._cleanup_driver_and_console()
104
68
 
105
- def _print_exit_reason_and_parts(self, final_event):
106
- exit_reason = (
107
- getattr(final_event, "metadata", {}).get("exit_reason")
108
- if hasattr(final_event, "metadata")
109
- else None
110
- )
111
- if exit_reason:
112
- print(f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]")
113
- parts = getattr(final_event, "parts", None)
114
- if not exit_reason:
115
- if parts is None or len(parts) == 0:
116
- shared_console.print(
117
- "[yellow]No output produced by the model.[/yellow]"
118
- )
119
- else:
120
- if hasattr(self.args, "verbose_agent") and self.args.verbose_agent:
121
- print(
122
- "[yellow]No user-visible output. Model returned the following parts:"
123
- )
124
- for idx, part in enumerate(parts):
125
- print(
126
- f" [part {idx}] type: {type(part).__name__} | content: {getattr(part, 'content', repr(part))}"
127
- )
128
69
 
129
70
  def _cleanup_driver_and_console(self):
130
71
  if hasattr(self.agent, "join_driver"):
@@ -6,7 +6,7 @@ from rich import print as rich_print
6
6
  from rich.align import Align
7
7
  from rich.panel import Panel
8
8
  from rich.text import Text
9
- from janito.version import __version__ as VERSION
9
+ from janito import __version__ as VERSION
10
10
  from janito.cli.utils import format_tokens
11
11
 
12
12
 
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
@@ -31,6 +31,19 @@ class ConfigManager:
31
31
  self.file_config = {}
32
32
  self.runtime_overrides = dict(runtime_overrides) if runtime_overrides else {}
33
33
  self._load_file_config()
34
+ self._apply_tool_permissions_on_startup()
35
+
36
+ def _apply_tool_permissions_on_startup(self):
37
+ # On startup, read tool_permissions from config and set global permissions
38
+ perm_str = self.file_config.get("tool_permissions")
39
+ if perm_str:
40
+ try:
41
+ from janito.tools.permissions_parse import parse_permissions_string
42
+ from janito.tools.permissions import set_global_allowed_permissions
43
+ perms = parse_permissions_string(perm_str)
44
+ set_global_allowed_permissions(perms)
45
+ except Exception as e:
46
+ print(f"Warning: Failed to apply tool_permissions from config: {e}")
34
47
 
35
48
  def _load_file_config(self):
36
49
  if self.config_path.exists():
@@ -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
+ )
Binary file
@@ -0,0 +1,20 @@
1
+ # OpenAI Driver Debugging
2
+
3
+ ## HTTP Debugging via Environment Variable
4
+
5
+ To debug HTTP requests and responses for the OpenAI driver, set the environment variable `OPENAI_DEBUG_HTTP=1` before running your application. This will print the full HTTP request and response bodies to the console for troubleshooting purposes.
6
+
7
+ **Example (PowerShell):**
8
+
9
+ ```
10
+ $env:OPENAI_DEBUG_HTTP=1
11
+ python your_app.py
12
+ ```
13
+
14
+ **Example (bash):**
15
+
16
+ ```
17
+ OPENAI_DEBUG_HTTP=1 python your_app.py
18
+ ```
19
+
20
+ This feature is implemented in `janito/drivers/openai/driver.py` and works by wrapping the OpenAI client HTTP transport with a debug logger when the environment variable is set.
Binary file
janito/event_bus/event.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import attr
2
2
  from typing import ClassVar
3
- from datetime import datetime
3
+ from datetime import datetime, timezone
4
4
 
5
5
 
6
6
  @attr.s(auto_attribs=True, kw_only=True)
@@ -12,4 +12,4 @@ class Event:
12
12
  """
13
13
 
14
14
  category: ClassVar[str] = "generic"
15
- timestamp: datetime = attr.ib(factory=datetime.utcnow)
15
+ timestamp: datetime = attr.ib(factory=lambda: datetime.now(timezone.utc))