janito 1.6.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 (117) hide show
  1. janito/__init__.py +1 -1
  2. janito/agent/config.py +3 -3
  3. janito/agent/config_defaults.py +3 -2
  4. janito/agent/conversation.py +73 -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 -6
  15. janito/agent/openai_schema_generator.py +23 -4
  16. janito/agent/platform_discovery.py +90 -0
  17. janito/agent/profile_manager.py +34 -110
  18. janito/agent/queued_message_handler.py +22 -3
  19. janito/agent/rich_message_handler.py +3 -1
  20. janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +14 -0
  21. janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +13 -0
  22. janito/agent/test_handler_protocols.py +47 -0
  23. janito/agent/tests/__init__.py +1 -0
  24. janito/agent/tool_base.py +1 -1
  25. janito/agent/tool_executor.py +109 -0
  26. janito/agent/tool_registry.py +3 -75
  27. janito/agent/tool_use_tracker.py +46 -0
  28. janito/agent/tools/__init__.py +11 -8
  29. janito/agent/tools/ask_user.py +26 -12
  30. janito/agent/tools/create_directory.py +50 -18
  31. janito/agent/tools/create_file.py +60 -29
  32. janito/agent/tools/dir_walk_utils.py +16 -0
  33. janito/agent/tools/fetch_url.py +10 -11
  34. janito/agent/tools/find_files.py +49 -40
  35. janito/agent/tools/get_lines.py +60 -25
  36. janito/agent/tools/memory.py +48 -0
  37. janito/agent/tools/move_file.py +72 -23
  38. janito/agent/tools/outline_file/__init__.py +85 -0
  39. janito/agent/tools/outline_file/formatting.py +20 -0
  40. janito/agent/tools/outline_file/markdown_outline.py +14 -0
  41. janito/agent/tools/outline_file/python_outline.py +71 -0
  42. janito/agent/tools/present_choices.py +62 -0
  43. janito/agent/tools/present_choices_test.py +18 -0
  44. janito/agent/tools/remove_directory.py +31 -26
  45. janito/agent/tools/remove_file.py +31 -13
  46. janito/agent/tools/replace_text_in_file.py +135 -36
  47. janito/agent/tools/run_bash_command.py +113 -97
  48. janito/agent/tools/run_powershell_command.py +169 -0
  49. janito/agent/tools/run_python_command.py +53 -29
  50. janito/agent/tools/search_outline.py +17 -0
  51. janito/agent/tools/search_text.py +208 -0
  52. janito/agent/tools/tools_utils.py +47 -4
  53. janito/agent/tools/utils.py +14 -15
  54. janito/agent/tools/validate_file_syntax.py +163 -0
  55. janito/cli/_print_config.py +1 -1
  56. janito/cli/arg_parser.py +36 -4
  57. janito/cli/config_commands.py +1 -1
  58. janito/cli/logging_setup.py +7 -2
  59. janito/cli/main.py +97 -3
  60. janito/cli/runner/__init__.py +0 -2
  61. janito/cli/runner/_termweb_log_utils.py +17 -0
  62. janito/cli/runner/cli_main.py +121 -89
  63. janito/cli/runner/config.py +6 -4
  64. janito/cli/termweb_starter.py +73 -0
  65. janito/cli_chat_shell/chat_loop.py +52 -13
  66. janito/cli_chat_shell/chat_state.py +1 -1
  67. janito/cli_chat_shell/chat_ui.py +2 -3
  68. janito/cli_chat_shell/commands/__init__.py +17 -6
  69. janito/cli_chat_shell/commands/{history_reset.py → history_start.py} +13 -5
  70. janito/cli_chat_shell/commands/lang.py +16 -0
  71. janito/cli_chat_shell/commands/prompt.py +42 -0
  72. janito/cli_chat_shell/commands/session_control.py +36 -1
  73. janito/cli_chat_shell/commands/sum.py +49 -0
  74. janito/cli_chat_shell/commands/termweb_log.py +86 -0
  75. janito/cli_chat_shell/commands/utility.py +5 -2
  76. janito/cli_chat_shell/commands/verbose.py +29 -0
  77. janito/cli_chat_shell/load_prompt.py +47 -8
  78. janito/cli_chat_shell/session_manager.py +9 -1
  79. janito/cli_chat_shell/shell_command_completer.py +20 -0
  80. janito/cli_chat_shell/ui.py +110 -93
  81. janito/i18n/__init__.py +35 -0
  82. janito/i18n/messages.py +23 -0
  83. janito/i18n/pt.py +46 -0
  84. janito/rich_utils.py +43 -43
  85. janito/termweb/app.py +95 -0
  86. janito/termweb/static/editor.html +238 -0
  87. janito/termweb/static/editor.html.bak +238 -0
  88. janito/termweb/static/explorer.html.bak +59 -0
  89. janito/termweb/static/favicon.ico +0 -0
  90. janito/termweb/static/favicon.ico.bak +0 -0
  91. janito/termweb/static/index.html +55 -0
  92. janito/termweb/static/index.html.bak +55 -0
  93. janito/termweb/static/index.html.bak.bak +175 -0
  94. janito/termweb/static/landing.html.bak +36 -0
  95. janito/termweb/static/termicon.svg +1 -0
  96. janito/termweb/static/termweb.css +235 -0
  97. janito/termweb/static/termweb.css.bak +286 -0
  98. janito/termweb/static/termweb.js +187 -0
  99. janito/termweb/static/termweb.js.bak +187 -0
  100. janito/termweb/static/termweb.js.bak.bak +157 -0
  101. janito/termweb/static/termweb_quickopen.js +135 -0
  102. janito/termweb/static/termweb_quickopen.js.bak +125 -0
  103. janito/web/app.py +10 -13
  104. {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/METADATA +73 -32
  105. janito-1.8.0.dist-info/RECORD +127 -0
  106. {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/WHEEL +1 -1
  107. janito/agent/tool_registry_core.py +0 -2
  108. janito/agent/tools/get_file_outline.py +0 -117
  109. janito/agent/tools/py_compile_file.py +0 -40
  110. janito/agent/tools/replace_file.py +0 -51
  111. janito/agent/tools/search_files.py +0 -71
  112. janito/cli/runner/scan.py +0 -44
  113. janito/cli_chat_shell/commands/system.py +0 -73
  114. janito-1.6.0.dist-info/RECORD +0 -81
  115. {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/entry_points.txt +0 -0
  116. {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/licenses/LICENSE +0 -0
  117. {janito-1.6.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
@@ -175,7 +175,7 @@ def handle_config_commands(args):
175
175
  Path(__file__).parent
176
176
  / "agent"
177
177
  / "templates"
178
- / "system_prompt_template.j2"
178
+ / "system_prompt_template_default.j2"
179
179
  )
180
180
  print(
181
181
  f"{key} = (default template path: {home_shorten(str(template_path))})"
@@ -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
@@ -3,10 +3,12 @@
3
3
  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
- from janito.cli.runner import run_cli
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):
@@ -1,2 +0,0 @@
1
- from .cli_main import run_cli
2
- from .formatting import format_tokens
@@ -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,142 +1,167 @@
1
1
  import sys
2
- import os
3
- from rich.console import Console
2
+ import socket
4
3
  from janito.agent.profile_manager import AgentProfileManager
5
4
  from janito.agent.runtime_config import unified_config, runtime_config
6
5
  from janito.agent.config import get_api_key
7
6
  from janito import __version__
8
- from .formatting import format_tokens
9
- from .scan import scan_project
10
- from .config import get_system_prompt_template
11
7
  from janito.agent.conversation_exceptions import (
12
8
  MaxRoundsExceededError,
13
9
  EmptyResponseError,
14
10
  ProviderError,
15
11
  )
16
12
 
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
+
17
19
  def run_cli(args):
18
20
  if args.version:
19
21
  print(f"janito version {__version__}")
20
22
  sys.exit(0)
21
23
 
22
- # --scan: auto-detect tech/skills and save to .janito/tech.txt
23
- if getattr(args, "scan", False):
24
- scan_project()
25
- 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)
26
27
 
27
- # Check for .janito/tech.txt and print a tip if missing
28
- tech_txt_path = os.path.join(".janito", "tech.txt")
29
- if not os.path.exists(tech_txt_path):
30
- print("⚠️ No tech.txt found in .janito.")
31
- print(
32
- "💡 Tip: Run with --scan first to auto-detect project tech/skills and improve results."
33
- )
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))
34
40
 
35
41
  role = args.role or unified_config.get("role", "software engineer")
36
-
37
- # Ensure runtime_config is updated so chat shell sees the role
38
42
  if args.role:
39
43
  runtime_config.set("role", args.role)
40
-
41
- # Set runtime_config['model'] if --model is provided (highest priority, session only)
42
44
  if getattr(args, "model", None):
43
45
  runtime_config.set("model", args.model)
44
-
45
- # Set runtime_config['max_tools'] if --max-tools is provided
46
46
  if getattr(args, "max_tools", None) is not None:
47
47
  runtime_config.set("max_tools", args.max_tools)
48
-
49
- # Set trust-tools mode if enabled
50
48
  if getattr(args, "trust_tools", False):
51
49
  runtime_config.set("trust_tools", True)
52
-
53
- # Get system prompt template (instructions/config logic)
54
- system_prompt_template = get_system_prompt_template(args, role)
55
-
56
- if args.show_system:
57
- api_key = get_api_key()
58
- model = unified_config.get("model")
59
- print("Model:", model)
60
- print("Parameters: {}")
61
- print(
62
- "System Prompt Template:",
63
- system_prompt_template or "(default system prompt template not provided)",
64
- )
65
- sys.exit(0)
66
-
67
- api_key = get_api_key()
68
- model = unified_config.get("model")
69
- base_url = unified_config.get("base_url", "https://openrouter.ai/api/v1")
70
- azure_openai_api_version = unified_config.get(
71
- "azure_openai_api_version", "2023-05-15"
72
- )
73
- # Handle vanilla mode
74
- vanilla_mode = getattr(args, "vanilla", False)
75
- if vanilla_mode:
76
- runtime_config.set("vanilla_mode", True)
77
- system_prompt_template = None
78
- runtime_config.set("system_prompt_template", None)
79
- if args.temperature is None:
80
- runtime_config.set("temperature", None)
81
- else:
82
- runtime_config.set("vanilla_mode", False)
83
-
84
- interaction_style = getattr(args, "style", None) or unified_config.get(
85
- "interaction_style", "default"
86
- )
87
-
88
50
  if not getattr(args, "prompt", None):
89
51
  interaction_mode = "chat"
90
52
  else:
91
53
  interaction_mode = "prompt"
92
-
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")
93
57
  profile_manager = AgentProfileManager(
94
- api_key=api_key,
95
- model=model,
58
+ api_key=get_api_key(),
59
+ model=unified_config.get("model"),
96
60
  role=role,
97
- interaction_style=interaction_style,
61
+ profile_name=profile,
98
62
  interaction_mode=interaction_mode,
99
63
  verbose_tools=args.verbose_tools,
100
- base_url=base_url,
101
- 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
+ ),
102
68
  use_azure_openai=unified_config.get("use_azure_openai", False),
69
+ lang=lang,
103
70
  )
104
71
  profile_manager.refresh_prompt()
105
-
72
+ if getattr(args, "show_system", False):
73
+ print(profile_manager.render_prompt())
74
+ sys.exit(0)
106
75
  if args.max_tokens is not None:
107
76
  runtime_config.set("max_tokens", args.max_tokens)
108
-
109
- if not getattr(args, "prompt", None):
110
- from janito.cli_chat_shell.chat_loop import start_chat_shell
111
-
112
- start_chat_shell(
113
- 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
114
111
  )
115
- 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
116
115
 
117
- prompt = args.prompt
118
- console = Console()
119
- from janito.agent.rich_message_handler import RichMessageHandler
116
+ local_config.set("termweb_last_running_port", selected_port)
117
+ local_config.save()
120
118
 
121
- message_handler = RichMessageHandler()
122
- messages = []
123
- if profile_manager.system_prompt_template:
124
- messages.append(
125
- {"role": "system", "content": profile_manager.system_prompt_template}
126
- )
127
- messages.append({"role": "user", "content": prompt})
119
+ # --- End termweb integration ---
128
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})
129
157
  try:
130
- max_rounds = runtime_config.get("max_rounds", 50)
131
- profile_manager.agent.handle_conversation(
158
+ max_rounds = 50
159
+ profile_manager.agent.chat(
132
160
  messages,
133
161
  message_handler=message_handler,
134
162
  spinner=True,
135
163
  max_rounds=max_rounds,
136
- verbose_response=getattr(args, "verbose_response", False),
137
- verbose_events=getattr(args, "verbose_events", False),
138
164
  stream=getattr(args, "stream", False),
139
- verbose_stream=getattr(args, "verbose_stream", False),
140
165
  )
141
166
  except MaxRoundsExceededError:
142
167
  console.print("[red]Max conversation rounds exceeded.[/red]")
@@ -145,4 +170,11 @@ def run_cli(args):
145
170
  except EmptyResponseError as e:
146
171
  console.print(f"[red]Error:[/red] {e}")
147
172
  except KeyboardInterrupt:
173
+ from rich.console import Console
174
+
175
+ console = Console()
148
176
  console.print("[yellow]Interrupted by user.[/yellow]")
177
+ finally:
178
+ if termweb_proc:
179
+ termweb_proc.terminate()
180
+ termweb_proc.wait()
@@ -1,8 +1,8 @@
1
- import os
2
1
  from janito.agent.profile_manager import AgentProfileManager
3
2
  from janito.agent.runtime_config import unified_config, runtime_config
4
3
  from janito.agent.config import get_api_key
5
4
 
5
+
6
6
  def get_system_prompt_template(args, role):
7
7
  system_prompt_template = None
8
8
  if getattr(args, "system_prompt_template_file", None):
@@ -22,12 +22,14 @@ 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),
29
- azure_openai_api_version=unified_config.get("azure_openai_api_version", None),
29
+ azure_openai_api_version=unified_config.get(
30
+ "azure_openai_api_version", "2023-05-15"
31
+ ),
30
32
  use_azure_openai=unified_config.get("use_azure_openai", False),
31
33
  )
32
- system_prompt_template = profile_manager.render_prompt()
34
+ system_prompt_template = profile_manager.system_prompt_template
33
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