janito 2.6.1__py3-none-any.whl → 2.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.
- janito/__init__.py +6 -7
- janito/__main__.py +4 -5
- janito/_version.py +55 -58
- janito/agent/setup_agent.py +308 -241
- janito/agent/templates/profiles/{system_prompt_template_software developer.txt.j2 → system_prompt_template_Developer_with_Python_Tools.txt.j2} +43 -39
- janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +3 -12
- janito/cli/__init__.py +9 -10
- janito/cli/chat_mode/bindings.py +38 -38
- janito/cli/chat_mode/chat_entry.py +21 -23
- janito/cli/chat_mode/prompt_style.py +22 -25
- janito/cli/chat_mode/script_runner.py +158 -154
- janito/cli/chat_mode/session.py +80 -35
- janito/cli/chat_mode/session_profile_select.py +61 -52
- janito/cli/chat_mode/shell/commands/__init__.py +1 -5
- janito/cli/chat_mode/shell/commands/_priv_check.py +1 -0
- janito/cli/chat_mode/shell/commands/bang.py +10 -3
- janito/cli/chat_mode/shell/commands/conversation_restart.py +24 -7
- janito/cli/chat_mode/shell/commands/execute.py +22 -7
- janito/cli/chat_mode/shell/commands/help.py +4 -1
- janito/cli/chat_mode/shell/commands/model.py +13 -5
- janito/cli/chat_mode/shell/commands/privileges.py +21 -0
- janito/cli/chat_mode/shell/commands/prompt.py +0 -2
- janito/cli/chat_mode/shell/commands/read.py +22 -5
- janito/cli/chat_mode/shell/commands/tools.py +15 -4
- janito/cli/chat_mode/shell/commands/write.py +22 -5
- janito/cli/chat_mode/shell/input_history.py +3 -1
- janito/cli/chat_mode/shell/session/manager.py +0 -2
- janito/cli/chat_mode/toolbar.py +25 -19
- janito/cli/cli_commands/list_models.py +1 -1
- janito/cli/cli_commands/list_providers.py +1 -0
- janito/cli/cli_commands/list_tools.py +35 -7
- janito/cli/cli_commands/model_utils.py +5 -3
- janito/cli/cli_commands/show_config.py +12 -0
- janito/cli/cli_commands/show_system_prompt.py +23 -9
- janito/cli/config.py +0 -13
- janito/cli/core/getters.py +2 -0
- janito/cli/core/runner.py +25 -8
- janito/cli/core/setters.py +13 -76
- janito/cli/main_cli.py +9 -25
- janito/cli/prompt_core.py +19 -18
- janito/cli/prompt_setup.py +6 -3
- janito/cli/rich_terminal_reporter.py +19 -5
- janito/cli/single_shot_mode/handler.py +104 -95
- janito/cli/verbose_output.py +5 -1
- janito/config_manager.py +4 -0
- janito/drivers/azure_openai/driver.py +27 -30
- janito/drivers/driver_registry.py +27 -27
- janito/drivers/openai/driver.py +452 -436
- janito/formatting_token.py +12 -4
- janito/llm/agent.py +15 -6
- janito/llm/driver.py +1 -0
- janito/provider_registry.py +139 -178
- janito/providers/__init__.py +2 -0
- janito/providers/anthropic/model_info.py +40 -41
- janito/providers/anthropic/provider.py +75 -80
- janito/providers/azure_openai/provider.py +9 -4
- janito/providers/deepseek/provider.py +5 -4
- janito/providers/google/model_info.py +4 -2
- janito/providers/google/provider.py +11 -5
- janito/providers/groq/__init__.py +1 -0
- janito/providers/groq/model_info.py +46 -0
- janito/providers/groq/provider.py +76 -0
- janito/providers/moonshotai/__init__.py +1 -0
- janito/providers/moonshotai/model_info.py +15 -0
- janito/providers/moonshotai/provider.py +89 -0
- janito/providers/openai/provider.py +6 -7
- janito/tools/__init__.py +2 -0
- janito/tools/adapters/local/__init__.py +67 -66
- janito/tools/adapters/local/adapter.py +21 -4
- janito/tools/adapters/local/ask_user.py +1 -0
- janito/tools/adapters/local/copy_file.py +1 -0
- janito/tools/adapters/local/create_directory.py +1 -0
- janito/tools/adapters/local/create_file.py +1 -0
- janito/tools/adapters/local/delete_text_in_file.py +2 -1
- janito/tools/adapters/local/fetch_url.py +1 -0
- janito/tools/adapters/local/find_files.py +7 -6
- janito/tools/adapters/local/get_file_outline/core.py +1 -0
- janito/tools/adapters/local/get_file_outline/java_outline.py +22 -15
- janito/tools/adapters/local/get_file_outline/search_outline.py +1 -0
- janito/tools/adapters/local/move_file.py +4 -3
- janito/tools/adapters/local/open_html_in_browser.py +15 -5
- janito/tools/adapters/local/open_url.py +1 -0
- janito/tools/adapters/local/python_code_run.py +1 -0
- janito/tools/adapters/local/python_command_run.py +1 -0
- janito/tools/adapters/local/python_file_run.py +1 -0
- janito/tools/adapters/local/read_files.py +55 -40
- janito/tools/adapters/local/remove_directory.py +1 -0
- janito/tools/adapters/local/remove_file.py +1 -0
- janito/tools/adapters/local/replace_text_in_file.py +4 -3
- janito/tools/adapters/local/run_bash_command.py +1 -0
- janito/tools/adapters/local/run_powershell_command.py +1 -0
- janito/tools/adapters/local/search_text/core.py +18 -17
- janito/tools/adapters/local/search_text/match_lines.py +5 -5
- janito/tools/adapters/local/search_text/pattern_utils.py +1 -1
- janito/tools/adapters/local/search_text/traverse_directory.py +7 -7
- janito/tools/adapters/local/validate_file_syntax/core.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/html_validator.py +8 -1
- janito/tools/disabled_tools.py +68 -0
- janito/tools/path_security.py +18 -11
- janito/tools/permissions.py +6 -0
- janito/tools/permissions_parse.py +4 -3
- janito/tools/tool_base.py +11 -5
- janito/tools/tool_use_tracker.py +1 -4
- janito/tools/tool_utils.py +1 -1
- janito/tools/tools_adapter.py +57 -25
- {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/METADATA +411 -417
- janito-2.8.0.dist-info/RECORD +202 -0
- janito/cli/chat_mode/shell/commands/livelogs.py +0 -49
- janito/drivers/mistralai/driver.py +0 -41
- janito/providers/mistralai/model_info.py +0 -37
- janito/providers/mistralai/provider.py +0 -72
- janito/providers/provider_static_info.py +0 -18
- janito-2.6.1.dist-info/RECORD +0 -199
- /janito/agent/templates/profiles/{system_prompt_template_assistant.txt.j2 → system_prompt_template_model_conversation_without_tools_or_context.txt.j2} +0 -0
- {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/WHEEL +0 -0
- {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/entry_points.txt +0 -0
- {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.6.1.dist-info → janito-2.8.0.dist-info}/top_level.txt +0 -0
@@ -1,21 +1,12 @@
|
|
1
|
-
|
2
|
-
ex. "Search in code" -> Python Developer -> find(*.py) | Java Developer -> find(*.java)
|
3
|
-
#}
|
4
|
-
You are: {{ role }}
|
1
|
+
You are: software developer
|
5
2
|
|
6
3
|
{# Improves tool selection and platform specific constrains, eg, path format, C:\ vs /path #}
|
7
|
-
{% if allowed_permissions and 'x' in allowed_permissions %}
|
8
4
|
You will be using the following environment:
|
9
|
-
Platform:
|
10
|
-
|
11
|
-
Shell/Environment: {{ shell_info }}
|
12
|
-
{% endif %}
|
13
|
-
|
5
|
+
Platform: Windows
|
6
|
+
Shell/Environment: PowerShell
|
14
7
|
|
15
8
|
|
16
|
-
{% if allowed_permissions and 'r' in allowed_permissions %}
|
17
9
|
Before answering map the questions to artifacts found in the current directory - the current project.
|
18
|
-
{% endif %}
|
19
10
|
|
20
11
|
Respond according to the following guidelines:
|
21
12
|
{% if allowed_permissions %}
|
janito/cli/__init__.py
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
# janito.cli package
|
2
|
-
from .utils import format_tokens, format_generation_time
|
3
|
-
|
4
|
-
__all__ = [
|
5
|
-
"setup_provider",
|
6
|
-
"setup_agent",
|
7
|
-
"format_tokens",
|
8
|
-
"format_generation_time",
|
9
|
-
]
|
10
|
-
|
1
|
+
# janito.cli package
|
2
|
+
from .utils import format_tokens, format_generation_time
|
3
|
+
|
4
|
+
__all__ = [
|
5
|
+
"setup_provider",
|
6
|
+
"setup_agent",
|
7
|
+
"format_tokens",
|
8
|
+
"format_generation_time",
|
9
|
+
]
|
janito/cli/chat_mode/bindings.py
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
-
"""
|
2
|
-
Key bindings for Janito Chat CLI.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from prompt_toolkit.key_binding import KeyBindings
|
6
|
-
from janito.tools.permissions import get_global_allowed_permissions
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
buf
|
17
|
-
buf.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
buf
|
23
|
-
buf.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
buf
|
29
|
-
buf.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
buf
|
35
|
-
buf.
|
36
|
-
|
37
|
-
|
38
|
-
|
1
|
+
"""
|
2
|
+
Key bindings for Janito Chat CLI.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from prompt_toolkit.key_binding import KeyBindings
|
6
|
+
from janito.tools.permissions import get_global_allowed_permissions
|
7
|
+
|
8
|
+
|
9
|
+
class KeyBindingsFactory:
|
10
|
+
@staticmethod
|
11
|
+
def create():
|
12
|
+
bindings = KeyBindings()
|
13
|
+
|
14
|
+
@bindings.add("c-y")
|
15
|
+
def _(event):
|
16
|
+
buf = event.app.current_buffer
|
17
|
+
buf.text = "Yes"
|
18
|
+
buf.validate_and_handle()
|
19
|
+
|
20
|
+
@bindings.add("c-n")
|
21
|
+
def _(event):
|
22
|
+
buf = event.app.current_buffer
|
23
|
+
buf.text = "No"
|
24
|
+
buf.validate_and_handle()
|
25
|
+
|
26
|
+
@bindings.add("f2")
|
27
|
+
def _(event):
|
28
|
+
buf = event.app.current_buffer
|
29
|
+
buf.text = "/restart"
|
30
|
+
buf.validate_and_handle()
|
31
|
+
|
32
|
+
@bindings.add("f12")
|
33
|
+
def _(event):
|
34
|
+
buf = event.app.current_buffer
|
35
|
+
buf.text = "Do It"
|
36
|
+
buf.validate_and_handle()
|
37
|
+
|
38
|
+
return bindings
|
@@ -1,23 +1,21 @@
|
|
1
|
-
"""
|
2
|
-
Main entry point for the Janito Chat CLI.
|
3
|
-
Handles the interactive chat loop and session startup.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from rich.console import Console
|
7
|
-
from prompt_toolkit.formatted_text import HTML
|
8
|
-
from janito.cli.chat_mode.session import ChatSession
|
9
|
-
|
10
|
-
|
11
|
-
def main(args=None):
|
12
|
-
console = Console()
|
13
|
-
console.clear()
|
14
|
-
from janito.version import __version__
|
15
|
-
|
16
|
-
|
17
|
-
session
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
main()
|
23
|
-
|
1
|
+
"""
|
2
|
+
Main entry point for the Janito Chat CLI.
|
3
|
+
Handles the interactive chat loop and session startup.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from rich.console import Console
|
7
|
+
from prompt_toolkit.formatted_text import HTML
|
8
|
+
from janito.cli.chat_mode.session import ChatSession
|
9
|
+
|
10
|
+
|
11
|
+
def main(args=None):
|
12
|
+
console = Console()
|
13
|
+
console.clear()
|
14
|
+
from janito.version import __version__
|
15
|
+
|
16
|
+
session = ChatSession(console, args=args)
|
17
|
+
session.run()
|
18
|
+
|
19
|
+
|
20
|
+
if __name__ == "__main__":
|
21
|
+
main()
|
@@ -1,25 +1,22 @@
|
|
1
|
-
from prompt_toolkit.styles import Style
|
2
|
-
|
3
|
-
chat_shell_style = Style.from_dict(
|
4
|
-
{
|
5
|
-
"prompt": "bg:#2323af #ffffff bold",
|
6
|
-
"": "bg:#005fdd #ffffff", # blue background for input area
|
7
|
-
"bottom-toolbar": "fg:#2323af bg:yellow",
|
8
|
-
"key-label": "bg:#ff9500 fg:#232323 bold",
|
9
|
-
"provider": "fg:#117fbf",
|
10
|
-
"model": "fg:#1f5fa9",
|
11
|
-
"role": "fg:#e87c32 bold",
|
12
|
-
"msg_count": "fg:#5454dd",
|
13
|
-
"session_id": "fg:#704ab9",
|
14
|
-
"tokens_total": "fg:#a022c7",
|
15
|
-
"tokens_in": "fg:#00af5f",
|
16
|
-
"tokens_out": "fg:#01814a",
|
17
|
-
"max-tokens": "fg:#888888",
|
18
|
-
|
19
|
-
|
20
|
-
"
|
21
|
-
|
22
|
-
|
23
|
-
}
|
24
|
-
)
|
25
|
-
|
1
|
+
from prompt_toolkit.styles import Style
|
2
|
+
|
3
|
+
chat_shell_style = Style.from_dict(
|
4
|
+
{
|
5
|
+
"prompt": "bg:#2323af #ffffff bold",
|
6
|
+
"": "bg:#005fdd #ffffff", # blue background for input area
|
7
|
+
"bottom-toolbar": "fg:#2323af bg:yellow",
|
8
|
+
"key-label": "bg:#ff9500 fg:#232323 bold",
|
9
|
+
"provider": "fg:#117fbf",
|
10
|
+
"model": "fg:#1f5fa9",
|
11
|
+
"role": "fg:#e87c32 bold",
|
12
|
+
"msg_count": "fg:#5454dd",
|
13
|
+
"session_id": "fg:#704ab9",
|
14
|
+
"tokens_total": "fg:#a022c7",
|
15
|
+
"tokens_in": "fg:#00af5f",
|
16
|
+
"tokens_out": "fg:#01814a",
|
17
|
+
"max-tokens": "fg:#888888",
|
18
|
+
"key-toggle-on": "bg:#ffd700 fg:#232323 bold",
|
19
|
+
"key-toggle-off": "bg:#444444 fg:#ffffff bold",
|
20
|
+
"cmd-label": "bg:#ff9500 fg:#232323 bold",
|
21
|
+
}
|
22
|
+
)
|
@@ -1,154 +1,158 @@
|
|
1
|
-
"""
|
2
|
-
Scripted runner for Janito chat mode.
|
3
|
-
|
4
|
-
This utility allows you to execute the interactive ``ChatSession`` logic with
|
5
|
-
an *in-memory* list of user inputs, making it much easier to write automated
|
6
|
-
unit or integration tests for the chat CLI without resorting to fragile
|
7
|
-
pseudo-terminal tricks.
|
8
|
-
|
9
|
-
The runner monkey-patches the private ``_handle_input`` method so that the
|
10
|
-
chat loop thinks it is receiving interactive input, while in reality the
|
11
|
-
values come from the provided list. All output is captured through a
|
12
|
-
``rich.console.Console`` instance configured with ``record=True`` so the test
|
13
|
-
can later inspect the rendered text.
|
14
|
-
|
15
|
-
Typical usage
|
16
|
-
-------------
|
17
|
-
>>> from janito.cli.chat_mode.script_runner import ChatScriptRunner
|
18
|
-
>>> inputs = ["Hello!", "/exit"]
|
19
|
-
>>> runner = ChatScriptRunner(inputs)
|
20
|
-
>>> transcript = runner.run()
|
21
|
-
>>> assert "Hello!" in transcript
|
22
|
-
|
23
|
-
The ``ChatScriptRunner`` purposefully replaces the internal call to the agent
|
24
|
-
with a real agent call by default. If you want to use a stub, you must modify the runner implementation.
|
25
|
-
"""
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
from
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
from janito.
|
35
|
-
from janito.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
"
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
class ChatScriptRunner:
|
48
|
-
"""Run a **ChatSession** non-interactively using a predefined set of inputs."""
|
49
|
-
|
50
|
-
def __init__(
|
51
|
-
self,
|
52
|
-
inputs: List[str],
|
53
|
-
*,
|
54
|
-
console: Optional[Console] = None,
|
55
|
-
provider: str = "openai",
|
56
|
-
model: str = "gpt-4.1",
|
57
|
-
use_real_agent: bool = True,
|
58
|
-
**chat_session_kwargs,
|
59
|
-
) -> None:
|
60
|
-
"""Create the runner.
|
61
|
-
|
62
|
-
Parameters
|
63
|
-
----------
|
64
|
-
inputs:
|
65
|
-
Ordered list of strings that will be fed to the chat loop.
|
66
|
-
console:
|
67
|
-
Optional *rich* console. If *None*, a new one is created with
|
68
|
-
*record=True* so that output can later be retrieved through
|
69
|
-
:py:meth:`rich.console.Console.export_text`.
|
70
|
-
use_real_agent:
|
71
|
-
chat_session_kwargs:
|
72
|
-
Extra keyword arguments forwarded to :class:`janito.cli.chat_mode.session.ChatSession`.
|
73
|
-
"""
|
74
|
-
self._input_queue = list(inputs)
|
75
|
-
self.console = console or Console(record=True)
|
76
|
-
self.provider = provider
|
77
|
-
self.model = model
|
78
|
-
self.use_real_agent = use_real_agent
|
79
|
-
# Ensure we always pass a non-interactive *args* namespace so that the
|
80
|
-
# normal ChatSession logic skips the Questionary profile prompt which
|
81
|
-
# is incompatible with headless test runs.
|
82
|
-
if "args" not in chat_session_kwargs or chat_session_kwargs["args"] is None:
|
83
|
-
from types import SimpleNamespace
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
#
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
1
|
+
"""
|
2
|
+
Scripted runner for Janito chat mode.
|
3
|
+
|
4
|
+
This utility allows you to execute the interactive ``ChatSession`` logic with
|
5
|
+
an *in-memory* list of user inputs, making it much easier to write automated
|
6
|
+
unit or integration tests for the chat CLI without resorting to fragile
|
7
|
+
pseudo-terminal tricks.
|
8
|
+
|
9
|
+
The runner monkey-patches the private ``_handle_input`` method so that the
|
10
|
+
chat loop thinks it is receiving interactive input, while in reality the
|
11
|
+
values come from the provided list. All output is captured through a
|
12
|
+
``rich.console.Console`` instance configured with ``record=True`` so the test
|
13
|
+
can later inspect the rendered text.
|
14
|
+
|
15
|
+
Typical usage
|
16
|
+
-------------
|
17
|
+
>>> from janito.cli.chat_mode.script_runner import ChatScriptRunner
|
18
|
+
>>> inputs = ["Hello!", "/exit"]
|
19
|
+
>>> runner = ChatScriptRunner(inputs)
|
20
|
+
>>> transcript = runner.run()
|
21
|
+
>>> assert "Hello!" in transcript
|
22
|
+
|
23
|
+
The ``ChatScriptRunner`` purposefully replaces the internal call to the agent
|
24
|
+
with a real agent call by default. If you want to use a stub, you must modify the runner implementation.
|
25
|
+
"""
|
26
|
+
|
27
|
+
from __future__ import annotations
|
28
|
+
|
29
|
+
from types import MethodType
|
30
|
+
from typing import List, Optional
|
31
|
+
|
32
|
+
from rich.console import Console
|
33
|
+
|
34
|
+
from janito.cli.chat_mode.session import ChatSession
|
35
|
+
from janito.provider_registry import ProviderRegistry
|
36
|
+
from janito.llm.driver_config import LLMDriverConfig
|
37
|
+
|
38
|
+
__all__ = ["ChatScriptRunner"]
|
39
|
+
|
40
|
+
|
41
|
+
auth_warning = (
|
42
|
+
"[yellow]ChatScriptRunner is executing in stubbed-agent mode; no calls to an "
|
43
|
+
"external LLM provider will be made.[/yellow]"
|
44
|
+
)
|
45
|
+
|
46
|
+
|
47
|
+
class ChatScriptRunner:
|
48
|
+
"""Run a **ChatSession** non-interactively using a predefined set of inputs."""
|
49
|
+
|
50
|
+
def __init__(
|
51
|
+
self,
|
52
|
+
inputs: List[str],
|
53
|
+
*,
|
54
|
+
console: Optional[Console] = None,
|
55
|
+
provider: str = "openai",
|
56
|
+
model: str = "gpt-4.1",
|
57
|
+
use_real_agent: bool = True,
|
58
|
+
**chat_session_kwargs,
|
59
|
+
) -> None:
|
60
|
+
"""Create the runner.
|
61
|
+
|
62
|
+
Parameters
|
63
|
+
----------
|
64
|
+
inputs:
|
65
|
+
Ordered list of strings that will be fed to the chat loop.
|
66
|
+
console:
|
67
|
+
Optional *rich* console. If *None*, a new one is created with
|
68
|
+
*record=True* so that output can later be retrieved through
|
69
|
+
:py:meth:`rich.console.Console.export_text`.
|
70
|
+
use_real_agent:
|
71
|
+
chat_session_kwargs:
|
72
|
+
Extra keyword arguments forwarded to :class:`janito.cli.chat_mode.session.ChatSession`.
|
73
|
+
"""
|
74
|
+
self._input_queue = list(inputs)
|
75
|
+
self.console = console or Console(record=True)
|
76
|
+
self.provider = provider
|
77
|
+
self.model = model
|
78
|
+
self.use_real_agent = use_real_agent
|
79
|
+
# Ensure we always pass a non-interactive *args* namespace so that the
|
80
|
+
# normal ChatSession logic skips the Questionary profile prompt which
|
81
|
+
# is incompatible with headless test runs.
|
82
|
+
if "args" not in chat_session_kwargs or chat_session_kwargs["args"] is None:
|
83
|
+
from types import SimpleNamespace
|
84
|
+
|
85
|
+
chat_session_kwargs["args"] = SimpleNamespace(
|
86
|
+
profile="developer",
|
87
|
+
provider=self.provider,
|
88
|
+
model=self.model,
|
89
|
+
)
|
90
|
+
|
91
|
+
# Create the ChatSession instance **after** we monkey-patch methods that rely on
|
92
|
+
# prompt-toolkit so that no attempt is made to instantiate terminal UIs in
|
93
|
+
# a headless environment like CI.
|
94
|
+
|
95
|
+
# 1) Patch *ChatSession._create_prompt_session* to do nothing – the
|
96
|
+
# interactive session object is irrelevant for scripted runs.
|
97
|
+
from types import MethodType as _MT
|
98
|
+
|
99
|
+
if "_original_create_prompt_session" not in ChatSession.__dict__:
|
100
|
+
ChatSession._original_create_prompt_session = ChatSession._create_prompt_session # type: ignore[attr-defined]
|
101
|
+
ChatSession._create_prompt_session = _MT(lambda _self: None, ChatSession) # type: ignore[method-assign]
|
102
|
+
|
103
|
+
# Resolve provider instance now so that ChatSession uses a ready agent
|
104
|
+
provider_instance = ProviderRegistry().get_instance(self.provider)
|
105
|
+
if provider_instance is None:
|
106
|
+
raise RuntimeError(
|
107
|
+
f"Provider '{self.provider}' is not available on this system."
|
108
|
+
)
|
109
|
+
driver_config = LLMDriverConfig(model=self.model)
|
110
|
+
chat_session_kwargs.setdefault("provider_instance", provider_instance)
|
111
|
+
chat_session_kwargs.setdefault("llm_driver_config", driver_config)
|
112
|
+
|
113
|
+
self.chat_session = ChatSession(console=self.console, **chat_session_kwargs)
|
114
|
+
|
115
|
+
# Monkey-patch the *ChatSession._handle_input* method so that it pops
|
116
|
+
# from our in-memory queue instead of reading from stdin.
|
117
|
+
def _script_handle_input(
|
118
|
+
this: ChatSession, _prompt_session_unused
|
119
|
+
): # noqa: D401
|
120
|
+
if not self._input_queue:
|
121
|
+
# Signal normal shutdown
|
122
|
+
this._handle_exit()
|
123
|
+
return None
|
124
|
+
return self._input_queue.pop(0)
|
125
|
+
|
126
|
+
# Bind the method to the *chat_session* instance.
|
127
|
+
self.chat_session._handle_input = MethodType( # type: ignore[assignment]
|
128
|
+
_script_handle_input, self.chat_session
|
129
|
+
)
|
130
|
+
|
131
|
+
# ---------------------------------------------------------------------
|
132
|
+
# Public helpers
|
133
|
+
# ---------------------------------------------------------------------
|
134
|
+
def run(self) -> str:
|
135
|
+
"""Execute the chat session and return the captured transcript."""
|
136
|
+
self.chat_session.run()
|
137
|
+
return self.console.export_text()
|
138
|
+
|
139
|
+
# ---------------------------------------------------------------------
|
140
|
+
# Helpers to introspect results
|
141
|
+
# ---------------------------------------------------------------------
|
142
|
+
def get_history(self):
|
143
|
+
"""Return the structured conversation history produced by the LLM."""
|
144
|
+
try:
|
145
|
+
return self.chat_session.shell_state.conversation_history.get_history()
|
146
|
+
except Exception:
|
147
|
+
return []
|
148
|
+
|
149
|
+
def get_last_response(self) -> str | None:
|
150
|
+
"""Return the *assistant* content of the last message, if any."""
|
151
|
+
history = self.get_history()
|
152
|
+
for message in reversed(history):
|
153
|
+
if message.get("role") == "assistant":
|
154
|
+
return message.get("content")
|
155
|
+
return None
|
156
|
+
|
157
|
+
# Convenience alias so tests can simply call *runner()*
|
158
|
+
__call__ = run
|