janito 1.7.0__py3-none-any.whl → 1.8.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 (115) hide show
  1. janito/__init__.py +1 -1
  2. janito/agent/config.py +1 -1
  3. janito/agent/config_defaults.py +2 -2
  4. janito/agent/conversation.py +70 -27
  5. janito/agent/conversation_api.py +104 -4
  6. janito/agent/conversation_exceptions.py +6 -0
  7. janito/agent/conversation_tool_calls.py +17 -3
  8. janito/agent/event.py +24 -0
  9. janito/agent/event_dispatcher.py +24 -0
  10. janito/agent/event_handler_protocol.py +5 -0
  11. janito/agent/event_system.py +15 -0
  12. janito/agent/message_handler.py +4 -1
  13. janito/agent/message_handler_protocol.py +5 -0
  14. janito/agent/openai_client.py +5 -8
  15. janito/agent/openai_schema_generator.py +23 -4
  16. janito/agent/profile_manager.py +15 -83
  17. janito/agent/queued_message_handler.py +22 -3
  18. janito/agent/rich_message_handler.py +66 -72
  19. janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +14 -0
  20. janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +13 -0
  21. janito/agent/test_handler_protocols.py +47 -0
  22. janito/agent/tests/__init__.py +1 -0
  23. janito/agent/tool_base.py +1 -1
  24. janito/agent/tool_executor.py +109 -0
  25. janito/agent/tool_registry.py +3 -75
  26. janito/agent/tool_use_tracker.py +46 -0
  27. janito/agent/tools/__init__.py +8 -9
  28. janito/agent/tools/ask_user.py +19 -11
  29. janito/agent/tools/create_directory.py +43 -28
  30. janito/agent/tools/create_file.py +60 -29
  31. janito/agent/tools/dir_walk_utils.py +16 -0
  32. janito/agent/tools/fetch_url.py +10 -11
  33. janito/agent/tools/find_files.py +49 -32
  34. janito/agent/tools/get_lines.py +54 -18
  35. janito/agent/tools/memory.py +32 -52
  36. janito/agent/tools/move_file.py +72 -23
  37. janito/agent/tools/outline_file/__init__.py +85 -0
  38. janito/agent/tools/outline_file/formatting.py +20 -0
  39. janito/agent/tools/outline_file/markdown_outline.py +14 -0
  40. janito/agent/tools/outline_file/python_outline.py +71 -0
  41. janito/agent/tools/present_choices.py +62 -0
  42. janito/agent/tools/present_choices_test.py +18 -0
  43. janito/agent/tools/remove_directory.py +31 -26
  44. janito/agent/tools/remove_file.py +31 -13
  45. janito/agent/tools/replace_text_in_file.py +135 -36
  46. janito/agent/tools/run_bash_command.py +47 -50
  47. janito/agent/tools/run_powershell_command.py +52 -36
  48. janito/agent/tools/run_python_command.py +49 -29
  49. janito/agent/tools/search_outline.py +17 -0
  50. janito/agent/tools/search_text.py +208 -0
  51. janito/agent/tools/tools_utils.py +47 -4
  52. janito/agent/tools/utils.py +14 -15
  53. janito/agent/tools/validate_file_syntax.py +163 -0
  54. janito/cli/arg_parser.py +36 -4
  55. janito/cli/logging_setup.py +7 -2
  56. janito/cli/main.py +96 -2
  57. janito/cli/runner/_termweb_log_utils.py +17 -0
  58. janito/cli/runner/cli_main.py +119 -77
  59. janito/cli/runner/config.py +2 -2
  60. janito/cli/termweb_starter.py +73 -0
  61. janito/cli_chat_shell/chat_loop.py +42 -7
  62. janito/cli_chat_shell/chat_state.py +1 -1
  63. janito/cli_chat_shell/chat_ui.py +0 -1
  64. janito/cli_chat_shell/commands/__init__.py +15 -6
  65. janito/cli_chat_shell/commands/{history_reset.py → history_start.py} +13 -5
  66. janito/cli_chat_shell/commands/lang.py +16 -0
  67. janito/cli_chat_shell/commands/prompt.py +42 -0
  68. janito/cli_chat_shell/commands/session_control.py +36 -1
  69. janito/cli_chat_shell/commands/termweb_log.py +86 -0
  70. janito/cli_chat_shell/commands/utility.py +5 -2
  71. janito/cli_chat_shell/commands/verbose.py +29 -0
  72. janito/cli_chat_shell/session_manager.py +9 -1
  73. janito/cli_chat_shell/shell_command_completer.py +20 -0
  74. janito/cli_chat_shell/ui.py +110 -99
  75. janito/i18n/__init__.py +35 -0
  76. janito/i18n/messages.py +23 -0
  77. janito/i18n/pt.py +46 -0
  78. janito/rich_utils.py +43 -43
  79. janito/termweb/app.py +95 -0
  80. janito/termweb/static/editor.html +238 -0
  81. janito/termweb/static/editor.html.bak +238 -0
  82. janito/termweb/static/explorer.html.bak +59 -0
  83. janito/termweb/static/favicon.ico +0 -0
  84. janito/termweb/static/favicon.ico.bak +0 -0
  85. janito/termweb/static/index.html +55 -0
  86. janito/termweb/static/index.html.bak +55 -0
  87. janito/termweb/static/index.html.bak.bak +175 -0
  88. janito/termweb/static/landing.html.bak +36 -0
  89. janito/termweb/static/termicon.svg +1 -0
  90. janito/termweb/static/termweb.css +235 -0
  91. janito/termweb/static/termweb.css.bak +286 -0
  92. janito/termweb/static/termweb.js +187 -0
  93. janito/termweb/static/termweb.js.bak +187 -0
  94. janito/termweb/static/termweb.js.bak.bak +157 -0
  95. janito/termweb/static/termweb_quickopen.js +135 -0
  96. janito/termweb/static/termweb_quickopen.js.bak +125 -0
  97. janito/web/app.py +4 -4
  98. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/METADATA +58 -25
  99. janito-1.8.0.dist-info/RECORD +127 -0
  100. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/WHEEL +1 -1
  101. janito/agent/templates/profiles/system_prompt_template_base.toml +0 -76
  102. janito/agent/templates/profiles/system_prompt_template_default.toml +0 -3
  103. janito/agent/templates/profiles/system_prompt_template_technical.toml +0 -13
  104. janito/agent/tests/test_prompt_toml.py +0 -61
  105. janito/agent/tool_registry_core.py +0 -2
  106. janito/agent/tools/get_file_outline.py +0 -146
  107. janito/agent/tools/py_compile_file.py +0 -40
  108. janito/agent/tools/replace_file.py +0 -51
  109. janito/agent/tools/search_files.py +0 -65
  110. janito/cli/runner/scan.py +0 -57
  111. janito/cli_chat_shell/commands/system.py +0 -73
  112. janito-1.7.0.dist-info/RECORD +0 -89
  113. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/entry_points.txt +0 -0
  114. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/licenses/LICENSE +0 -0
  115. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/top_level.txt +0 -0
janito/cli/arg_parser.py CHANGED
@@ -2,12 +2,21 @@ import argparse
2
2
 
3
3
 
4
4
  def create_parser():
5
+ # Adiciona --list-tools para listar ferramentas registradas
6
+ # (adição incremental segura)
7
+
5
8
  parser = argparse.ArgumentParser(
6
9
  description="OpenRouter API call using OpenAI Python SDK"
7
10
  )
8
11
  parser.add_argument(
9
12
  "prompt", type=str, nargs="?", help="Prompt to send to the model"
10
13
  )
14
+ parser.add_argument(
15
+ "--lang",
16
+ type=str,
17
+ default=None,
18
+ help="Language for interface messages (e.g., en, pt). Overrides config if set.",
19
+ )
11
20
 
12
21
  parser.add_argument(
13
22
  "--max-tokens",
@@ -23,6 +32,7 @@ def create_parser():
23
32
  )
24
33
  parser.add_argument(
25
34
  "--model",
35
+ "-m",
26
36
  type=str,
27
37
  default=None,
28
38
  help="Model name to use for this session (overrides config, does not persist)",
@@ -77,11 +87,21 @@ def create_parser():
77
87
  action="store_true",
78
88
  help="Pretty print the full response object",
79
89
  )
90
+ parser.add_argument(
91
+ "--list-tools",
92
+ action="store_true",
93
+ help="Lista todas as ferramentas registradas e sai.",
94
+ )
80
95
  parser.add_argument(
81
96
  "--show-system",
82
97
  action="store_true",
83
98
  help="Show model, parameters, system prompt, and tool definitions, then exit",
84
99
  )
100
+ parser.add_argument(
101
+ "--verbose-reason",
102
+ action="store_true",
103
+ help="Print the tool call reason whenever a tool is invoked (for debugging)",
104
+ )
85
105
  parser.add_argument(
86
106
  "--verbose-tools",
87
107
  action="store_true",
@@ -169,10 +189,10 @@ def create_parser():
169
189
  help="Suppress all tool output (trusted tools mode: only shows output file locations)",
170
190
  )
171
191
  parser.add_argument(
172
- "--style",
192
+ "--profile",
173
193
  type=str,
174
194
  default=None,
175
- help="Interaction style for system prompt template (e.g., default, technical)",
195
+ help="Agent Profile name (only 'base' is supported)",
176
196
  )
177
197
  parser.add_argument(
178
198
  "--stream",
@@ -185,8 +205,20 @@ def create_parser():
185
205
  help="Print raw chunks as they are fetched from OpenAI (for debugging)",
186
206
  )
187
207
  parser.add_argument(
188
- "--scan",
208
+ "--no-termweb",
209
+ action="store_true",
210
+ help="Disable the built-in lightweight web file viewer for terminal links (enabled by default)",
211
+ )
212
+ parser.add_argument(
213
+ "--termweb-port",
214
+ type=int,
215
+ default=8088,
216
+ help="Port for the termweb server (default: 8088)",
217
+ )
218
+ parser.add_argument(
219
+ "-i",
220
+ "--info",
189
221
  action="store_true",
190
- help="Scan the project to auto-detect relevant tech/skills and save to .janito/tech.txt (no chat)",
222
+ help="Exibe informações básicas do programa e sai (útil para execução única em shell)",
191
223
  )
192
224
  return parser
@@ -2,8 +2,13 @@ import os
2
2
  import logging
3
3
 
4
4
 
5
+ from janito.agent.runtime_config import runtime_config
6
+
7
+
5
8
  def setup_verbose_logging(args):
6
- if args.verbose_http or args.verbose_http_raw:
9
+ if runtime_config.get("verbose_http", False) or runtime_config.get(
10
+ "verbose_http_raw", False
11
+ ):
7
12
  httpx_logger = logging.getLogger("httpx")
8
13
  httpx_logger.setLevel(logging.DEBUG)
9
14
  handler = logging.StreamHandler()
@@ -12,7 +17,7 @@ def setup_verbose_logging(args):
12
17
  )
13
18
  httpx_logger.addHandler(handler)
14
19
 
15
- if args.verbose_http_raw:
20
+ if runtime_config.get("verbose_http_raw", False):
16
21
  os.environ["HTTPX_LOG_LEVEL"] = "trace"
17
22
 
18
23
  httpcore_logger = logging.getLogger("httpcore")
janito/cli/main.py CHANGED
@@ -4,9 +4,11 @@ from janito.cli.arg_parser import create_parser
4
4
  from janito.cli.config_commands import handle_config_commands
5
5
  from janito.cli.logging_setup import setup_verbose_logging
6
6
  from janito.cli.runner.cli_main import run_cli
7
+ from janito.agent.runtime_config import unified_config
7
8
 
8
9
  # Ensure all tools are registered at startup
9
10
  import janito.agent.tools # noqa: F401
11
+ from janito.i18n import tr
10
12
 
11
13
 
12
14
  def main():
@@ -14,6 +16,8 @@ def main():
14
16
  import sys
15
17
 
16
18
  from janito.agent.config import local_config, global_config
19
+ import janito.i18n as i18n
20
+ from janito.agent.runtime_config import runtime_config
17
21
 
18
22
  local_config.load()
19
23
  global_config.load()
@@ -21,16 +25,106 @@ def main():
21
25
  parser = create_parser()
22
26
  args = parser.parse_args()
23
27
 
28
+ # Seleção de idioma: prioridade --lang > config.json > padrão
29
+ lang = getattr(args, "lang", None) or unified_config.get("lang", None) or "en"
30
+ runtime_config.set("lang", lang)
31
+ i18n.set_locale(lang)
32
+
24
33
  from janito.agent.config import CONFIG_OPTIONS
25
34
  from janito.agent.config_defaults import CONFIG_DEFAULTS
26
35
 
27
36
  if getattr(args, "help_config", False):
28
- print("Available configuration options:\n")
37
+ print(tr("Available configuration options:\n"))
29
38
  for key, desc in CONFIG_OPTIONS.items():
30
39
  default = CONFIG_DEFAULTS.get(key, None)
31
- print(f"{key:15} {desc} (default: {default})")
40
+ print(
41
+ tr(
42
+ "{key:15} {desc} (default: {default})",
43
+ key=key,
44
+ desc=desc,
45
+ default=default,
46
+ )
47
+ )
48
+ sys.exit(0)
49
+
50
+ if getattr(args, "list_tools", False):
51
+ from janito.agent.tool_registry import get_tool_schemas
52
+ from rich.console import Console
53
+ from rich.table import Table
54
+
55
+ console = Console()
56
+ table = Table(
57
+ title="Ferramentas Registradas", show_lines=True, style="bold magenta"
58
+ )
59
+ table.add_column("Gnome", style="cyan", no_wrap=True)
60
+ table.add_column("Descrição", style="green")
61
+ table.add_column("Parâmetros", style="yellow")
62
+ for schema in get_tool_schemas():
63
+ fn = schema["function"]
64
+ params = "\n".join(
65
+ [
66
+ f"[bold]{k}[/]: {v['type']}"
67
+ for k, v in fn["parameters"].get("properties", {}).items()
68
+ ]
69
+ )
70
+ table.add_row(f"[b]{fn['name']}[/b]", fn["description"], params or "-")
71
+ console.print(table)
72
+ sys.exit(0)
73
+
74
+ if getattr(args, "info", False):
75
+ # (mantém bloco info)
76
+
77
+ print("Janito - Agente CLI de automação")
78
+ print(f"Modelo: {unified_config.get('model')}")
79
+ print(f"Temperatura: {unified_config.get('temperature')}")
80
+ print(f"Max tokens: {unified_config.get('max_tokens')}")
81
+ # System prompt real via AgentProfileManager
82
+ # Prioridade: --system-file > --system > AgentProfileManager
83
+ from janito.agent.runtime_config import runtime_config
84
+
85
+ system_prompt_val = None
86
+ origem = None
87
+ if getattr(args, "system_file", None):
88
+ try:
89
+ with open(args.system_file, "r", encoding="utf-8") as f:
90
+ system_prompt_val = f.read().strip()
91
+ runtime_config.set("system_prompt_template", system_prompt_val)
92
+ origem = "--system-file"
93
+ except Exception as e:
94
+ print(f"System prompt: (error reading system-file: {e})")
95
+ elif getattr(args, "system", None):
96
+ system_prompt_val = args.system
97
+ runtime_config.set("system_prompt_template", system_prompt_val)
98
+ origem = "--system"
99
+ else:
100
+ system_prompt_val = runtime_config.get("system_prompt_template")
101
+ if system_prompt_val:
102
+ origem = "runtime_config"
103
+ if system_prompt_val:
104
+ print(f"System prompt ({origem or 'runtime_config'}): {system_prompt_val}")
105
+ else:
106
+ try:
107
+ from janito.agent.profile_manager import AgentProfileManager
108
+ from janito.agent.config import get_api_key
109
+
110
+ role = args.role or unified_config.get("role", "software engineer")
111
+ interaction_mode = (
112
+ "chat" if not getattr(args, "prompt", None) else "prompt"
113
+ )
114
+ profile = "base"
115
+ profile_manager = AgentProfileManager(
116
+ api_key=get_api_key(),
117
+ model=unified_config.get("model"),
118
+ )
119
+ system_prompt_val = profile_manager.get_system_prompt(
120
+ role, interaction_mode, profile
121
+ )
122
+ print(f"System prompt (profile_manager): {system_prompt_val}")
123
+ except Exception as e:
124
+ print(f"System prompt: (error obtaining from profile_manager: {e})")
32
125
  sys.exit(0)
33
126
 
127
+ # ... resto do main ...
34
128
  handle_config_commands(args)
35
129
  setup_verbose_logging(args)
36
130
  if getattr(args, "web", False):
@@ -0,0 +1,17 @@
1
+ def print_termweb_logs(stdout_path, stderr_path, console):
2
+ try:
3
+ with open(stdout_path, encoding="utf-8") as f:
4
+ stdout_content = f.read().strip()
5
+ except Exception:
6
+ stdout_content = None
7
+ try:
8
+ with open(stderr_path, encoding="utf-8") as f:
9
+ stderr_content = f.read().strip()
10
+ except Exception:
11
+ stderr_content = None
12
+ if stdout_content:
13
+ console.print("[yellow][termweb][stdout] Output:\n" + stdout_content)
14
+ if stderr_content:
15
+ console.print("[red][termweb][stderr] Errors:\n" + stderr_content)
16
+ if not stdout_content and not stderr_content:
17
+ console.print("[termweb] No output or errors captured in logs.")
@@ -1,11 +1,9 @@
1
1
  import sys
2
- from rich.console import Console
2
+ import socket
3
3
  from janito.agent.profile_manager import AgentProfileManager
4
4
  from janito.agent.runtime_config import unified_config, runtime_config
5
5
  from janito.agent.config import get_api_key
6
6
  from janito import __version__
7
- from .scan import scan_project
8
- from .config import get_system_prompt_template
9
7
  from janito.agent.conversation_exceptions import (
10
8
  MaxRoundsExceededError,
11
9
  EmptyResponseError,
@@ -13,110 +11,149 @@ from janito.agent.conversation_exceptions import (
13
11
  )
14
12
 
15
13
 
14
+ def is_port_free(port):
15
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
16
+ return s.connect_ex(("localhost", port)) != 0
17
+
18
+
16
19
  def run_cli(args):
17
20
  if args.version:
18
21
  print(f"janito version {__version__}")
19
22
  sys.exit(0)
20
23
 
21
- # --scan: auto-detect tech/skills and save to .janito/tech.txt
22
- if getattr(args, "scan", False):
23
- scan_project()
24
- sys.exit(0)
24
+ # Set vanilla mode if -V/--vanilla is passed
25
+ if getattr(args, "vanilla", False):
26
+ runtime_config.set("vanilla_mode", True)
25
27
 
26
- role = args.role or unified_config.get("role", "software engineer")
28
+ # Normalize all verbose flags into runtime_config
29
+ for flag in [
30
+ "verbose_http",
31
+ "verbose_http_raw",
32
+ "verbose_response",
33
+ "verbose_reason",
34
+ "verbose_tools",
35
+ "verbose_events",
36
+ "verbose_stream",
37
+ ]:
38
+ if hasattr(args, flag):
39
+ runtime_config.set(flag, getattr(args, flag, False))
27
40
 
28
- # Ensure runtime_config is updated so chat shell sees the role
41
+ role = args.role or unified_config.get("role", "software engineer")
29
42
  if args.role:
30
43
  runtime_config.set("role", args.role)
31
-
32
- # Set runtime_config['model'] if --model is provided (highest priority, session only)
33
44
  if getattr(args, "model", None):
34
45
  runtime_config.set("model", args.model)
35
-
36
- # Set runtime_config['max_tools'] if --max-tools is provided
37
46
  if getattr(args, "max_tools", None) is not None:
38
47
  runtime_config.set("max_tools", args.max_tools)
39
-
40
- # Set trust-tools mode if enabled
41
48
  if getattr(args, "trust_tools", False):
42
49
  runtime_config.set("trust_tools", True)
43
-
44
- # Get system prompt template (instructions/config logic)
45
- system_prompt_template = get_system_prompt_template(args, role)
46
-
47
- if args.show_system:
48
- api_key = get_api_key()
49
- model = unified_config.get("model")
50
- print("Model:", model)
51
- print("Parameters: {}")
52
- print(
53
- "System Prompt Template:",
54
- system_prompt_template or "(default system prompt template not provided)",
55
- )
56
- sys.exit(0)
57
-
58
- api_key = get_api_key()
59
- model = unified_config.get("model")
60
- base_url = unified_config.get("base_url", "https://openrouter.ai/api/v1")
61
- azure_openai_api_version = unified_config.get(
62
- "azure_openai_api_version", "2023-05-15"
63
- )
64
- # Handle vanilla mode
65
- vanilla_mode = getattr(args, "vanilla", False)
66
- if vanilla_mode:
67
- runtime_config.set("vanilla_mode", True)
68
- system_prompt_template = None
69
- runtime_config.set("system_prompt_template", None)
70
- if args.temperature is None:
71
- runtime_config.set("temperature", None)
72
- else:
73
- runtime_config.set("vanilla_mode", False)
74
-
75
- interaction_style = getattr(args, "style", None) or unified_config.get(
76
- "interaction_style", "default"
77
- )
78
-
79
50
  if not getattr(args, "prompt", None):
80
51
  interaction_mode = "chat"
81
52
  else:
82
53
  interaction_mode = "prompt"
83
-
54
+ profile = "base"
55
+ # PATCH: Pass lang from args or runtime_config to AgentProfileManager
56
+ lang = getattr(args, "lang", None) or runtime_config.get("lang", "en")
84
57
  profile_manager = AgentProfileManager(
85
- api_key=api_key,
86
- model=model,
58
+ api_key=get_api_key(),
59
+ model=unified_config.get("model"),
87
60
  role=role,
88
- interaction_style=interaction_style,
61
+ profile_name=profile,
89
62
  interaction_mode=interaction_mode,
90
63
  verbose_tools=args.verbose_tools,
91
- base_url=base_url,
92
- azure_openai_api_version=azure_openai_api_version,
64
+ base_url=unified_config.get("base_url", "https://openrouter.ai/api/v1"),
65
+ azure_openai_api_version=unified_config.get(
66
+ "azure_openai_api_version", "2023-05-15"
67
+ ),
93
68
  use_azure_openai=unified_config.get("use_azure_openai", False),
69
+ lang=lang,
94
70
  )
95
71
  profile_manager.refresh_prompt()
96
-
72
+ if getattr(args, "show_system", False):
73
+ print(profile_manager.render_prompt())
74
+ sys.exit(0)
97
75
  if args.max_tokens is not None:
98
76
  runtime_config.set("max_tokens", args.max_tokens)
99
-
100
- if not getattr(args, "prompt", None):
101
- from janito.cli_chat_shell.chat_loop import start_chat_shell
102
-
103
- start_chat_shell(
104
- profile_manager, continue_session=getattr(args, "continue_session", False)
77
+ if getattr(args, "verbose_reason", False):
78
+ runtime_config.set("verbose_reason", True)
79
+
80
+ # --- Liteweb integration ---
81
+ termweb_proc = None
82
+ selected_port = None
83
+ if (
84
+ not getattr(args, "no_termweb", False)
85
+ and interaction_mode == "chat"
86
+ and not runtime_config.get("vanilla_mode", False)
87
+ ):
88
+ default_port = 8088
89
+ max_port = 8100
90
+ requested_port = args.termweb_port
91
+ if requested_port == default_port:
92
+ for port in range(default_port, max_port + 1):
93
+ if is_port_free(port):
94
+ selected_port = port
95
+ break
96
+ if selected_port is None:
97
+ print(
98
+ f"[red]No free port found for termweb in range {default_port}-{max_port}.[/red]"
99
+ )
100
+ sys.exit(1)
101
+ else:
102
+ if not is_port_free(requested_port):
103
+ print(f"[red]Port {requested_port} is not available for termweb.[/red]")
104
+ sys.exit(1)
105
+ selected_port = requested_port
106
+ runtime_config.set("termweb_port", selected_port)
107
+ from janito.cli.termweb_starter import start_termweb
108
+
109
+ termweb_proc, started, termweb_stdout_path, termweb_stderr_path = start_termweb(
110
+ selected_port
105
111
  )
106
- sys.exit(0)
112
+ # Store last running port in .janito/config.json if started
113
+ if started:
114
+ from janito.agent.config import local_config
107
115
 
108
- prompt = args.prompt
109
- console = Console()
110
- from janito.agent.rich_message_handler import RichMessageHandler
116
+ local_config.set("termweb_last_running_port", selected_port)
117
+ local_config.save()
111
118
 
112
- message_handler = RichMessageHandler()
113
- messages = []
114
- if profile_manager.system_prompt_template:
115
- messages.append(
116
- {"role": "system", "content": profile_manager.system_prompt_template}
117
- )
118
- messages.append({"role": "user", "content": prompt})
119
+ # --- End termweb integration ---
119
120
  try:
121
+ if not getattr(args, "prompt", None):
122
+ from janito.cli_chat_shell.chat_loop import start_chat_shell
123
+
124
+ start_chat_shell(
125
+ profile_manager,
126
+ continue_session=getattr(args, "continue_session", False),
127
+ termweb_stdout_path=(
128
+ termweb_stdout_path if "termweb_stdout_path" in locals() else None
129
+ ),
130
+ termweb_stderr_path=(
131
+ termweb_stderr_path if "termweb_stderr_path" in locals() else None
132
+ ),
133
+ )
134
+ sys.exit(0)
135
+ # --- Prompt mode ---
136
+ prompt = args.prompt
137
+ from rich.console import Console
138
+ from janito.agent.rich_message_handler import RichMessageHandler
139
+
140
+ console = Console()
141
+ message_handler = RichMessageHandler()
142
+ messages = []
143
+ system_prompt_override = runtime_config.get("system_prompt_template")
144
+ if system_prompt_override:
145
+ # Só adiciona system prompt se NÃO for vanilla, ou se foi explicitamente passado via --system
146
+ if not runtime_config.get("vanilla_mode", False) or getattr(
147
+ args, "system", None
148
+ ):
149
+ messages.append({"role": "system", "content": system_prompt_override})
150
+ elif profile_manager.system_prompt_template and not runtime_config.get(
151
+ "vanilla_mode", False
152
+ ):
153
+ messages.append(
154
+ {"role": "system", "content": profile_manager.system_prompt_template}
155
+ )
156
+ messages.append({"role": "user", "content": prompt})
120
157
  try:
121
158
  max_rounds = 50
122
159
  profile_manager.agent.chat(
@@ -124,8 +161,6 @@ def run_cli(args):
124
161
  message_handler=message_handler,
125
162
  spinner=True,
126
163
  max_rounds=max_rounds,
127
- verbose_response=getattr(args, "verbose_response", False),
128
- verbose_events=getattr(args, "verbose_events", False),
129
164
  stream=getattr(args, "stream", False),
130
165
  )
131
166
  except MaxRoundsExceededError:
@@ -135,4 +170,11 @@ def run_cli(args):
135
170
  except EmptyResponseError as e:
136
171
  console.print(f"[red]Error:[/red] {e}")
137
172
  except KeyboardInterrupt:
173
+ from rich.console import Console
174
+
175
+ console = Console()
138
176
  console.print("[yellow]Interrupted by user.[/yellow]")
177
+ finally:
178
+ if termweb_proc:
179
+ termweb_proc.terminate()
180
+ termweb_proc.wait()
@@ -22,7 +22,7 @@ def get_system_prompt_template(args, role):
22
22
  api_key=get_api_key(),
23
23
  model=unified_config.get("model"),
24
24
  role=role,
25
- interaction_style=unified_config.get("interaction_style", "default"),
25
+ profile_name="base",
26
26
  interaction_mode=unified_config.get("interaction_mode", "prompt"),
27
27
  verbose_tools=unified_config.get("verbose_tools", False),
28
28
  base_url=unified_config.get("base_url", None),
@@ -31,5 +31,5 @@ def get_system_prompt_template(args, role):
31
31
  ),
32
32
  use_azure_openai=unified_config.get("use_azure_openai", False),
33
33
  )
34
- system_prompt_template = profile_manager.render_prompt()
34
+ system_prompt_template = profile_manager.system_prompt_template
35
35
  return system_prompt_template
@@ -0,0 +1,73 @@
1
+ import sys
2
+ import subprocess
3
+ import tempfile
4
+ import time
5
+ import http.client
6
+ import os
7
+ from rich.console import Console
8
+ from janito.cli.runner._termweb_log_utils import print_termweb_logs
9
+ from janito.i18n import tr
10
+
11
+
12
+ def wait_for_termweb(port, timeout=3.0):
13
+ """Polls the Bottle app root endpoint until it responds or timeout (seconds) is reached."""
14
+ deadline = time.time() + timeout
15
+ while time.time() < deadline:
16
+ try:
17
+ conn = http.client.HTTPConnection("localhost", port, timeout=0.5)
18
+ conn.request("GET", "/")
19
+ resp = conn.getresponse()
20
+ if resp.status == 200:
21
+ return True
22
+ except Exception:
23
+ pass
24
+ time.sleep(0.1)
25
+ return False
26
+
27
+
28
+ def start_termweb(selected_port):
29
+ """
30
+ Start the termweb server on the given port, with rich spinner and logging.
31
+ Returns (termweb_proc, started: bool)
32
+ """
33
+ console = Console()
34
+ with console.status("[cyan]Starting web server...", spinner="dots"):
35
+ # Step 1: Try source path
36
+ app_py_path = os.path.join(os.path.dirname(__file__), "..", "termweb", "app.py")
37
+ app_py_path = os.path.abspath(app_py_path)
38
+ if not os.path.isfile(app_py_path):
39
+ # Step 2: Try installed package
40
+ try:
41
+ import janito_termweb
42
+
43
+ app_py_path = janito_termweb.__file__.replace("__init__.py", "app.py")
44
+ except ImportError:
45
+ console.print("[red]Could not find termweb app.py![/red]")
46
+ return None, False, None, None
47
+ termweb_stdout = tempfile.NamedTemporaryFile(
48
+ delete=False, mode="w+", encoding="utf-8"
49
+ )
50
+ termweb_stderr = tempfile.NamedTemporaryFile(
51
+ delete=False, mode="w+", encoding="utf-8"
52
+ )
53
+ termweb_proc = subprocess.Popen(
54
+ [sys.executable, app_py_path, "--port", str(selected_port)],
55
+ stdout=termweb_stdout,
56
+ stderr=termweb_stderr,
57
+ )
58
+ if wait_for_termweb(selected_port, timeout=3.0):
59
+ console.print(
60
+ tr(
61
+ "TermWeb started... Available at http://localhost:{selected_port}",
62
+ selected_port=selected_port,
63
+ )
64
+ )
65
+ return termweb_proc, True, termweb_stdout.name, termweb_stderr.name
66
+ else:
67
+ termweb_proc.terminate()
68
+ termweb_proc.wait()
69
+ console.print(
70
+ f"[red]Failed to start TermWeb on port {selected_port}. Check logs for details.[/red]"
71
+ )
72
+ print_termweb_logs(termweb_stdout.name, termweb_stderr.name)
73
+ return None, False, termweb_stdout.name, termweb_stderr.name