janito 2.6.1__py3-none-any.whl → 2.7.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 +7 -7
- janito/__main__.py +5 -5
- janito/_version.py +58 -58
- janito/agent/setup_agent.py +240 -240
- janito/agent/templates/profiles/{system_prompt_template_software developer.txt.j2 → system_prompt_template_plain_software_developer.txt.j2} +39 -39
- janito/cli/__init__.py +10 -10
- janito/cli/chat_mode/bindings.py +38 -38
- janito/cli/chat_mode/chat_entry.py +23 -23
- janito/cli/chat_mode/prompt_style.py +25 -25
- janito/cli/chat_mode/script_runner.py +154 -154
- janito/cli/chat_mode/session.py +1 -1
- janito/cli/chat_mode/session_profile_select.py +5 -5
- janito/cli/single_shot_mode/handler.py +95 -95
- janito/drivers/driver_registry.py +27 -27
- janito/drivers/openai/driver.py +435 -435
- janito/provider_registry.py +178 -178
- janito/providers/__init__.py +1 -0
- janito/providers/anthropic/model_info.py +41 -41
- janito/providers/anthropic/provider.py +80 -80
- janito/providers/moonshotai/__init__.py +1 -0
- janito/providers/moonshotai/model_info.py +15 -0
- janito/providers/moonshotai/provider.py +82 -0
- janito/providers/openai/model_info.py +1 -0
- janito/providers/provider_static_info.py +21 -18
- janito/tools/adapters/local/__init__.py +66 -66
- janito/tools/adapters/local/move_file.py +3 -3
- janito/tools/adapters/local/read_files.py +40 -40
- {janito-2.6.1.dist-info → janito-2.7.0.dist-info}/METADATA +419 -417
- {janito-2.6.1.dist-info → janito-2.7.0.dist-info}/RECORD +33 -30
- {janito-2.6.1.dist-info → janito-2.7.0.dist-info}/WHEEL +0 -0
- {janito-2.6.1.dist-info → janito-2.7.0.dist-info}/entry_points.txt +0 -0
- {janito-2.6.1.dist-info → janito-2.7.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.6.1.dist-info → janito-2.7.0.dist-info}/top_level.txt +0 -0
janito/__init__.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
"""
|
2
|
-
janito: A Python package for managing and interacting with Large Language Model (LLM) providers and their APIs.
|
3
|
-
Provides a CLI for credential management and an extensible driver system for LLMs.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from ._version import __version__
|
7
|
-
|
1
|
+
"""
|
2
|
+
janito: A Python package for managing and interacting with Large Language Model (LLM) providers and their APIs.
|
3
|
+
Provides a CLI for credential management and an extensible driver system for LLMs.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from ._version import __version__
|
7
|
+
|
janito/__main__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
from .cli.main import main
|
2
|
-
|
3
|
-
if __name__ == "__main__":
|
4
|
-
main()
|
5
|
-
|
1
|
+
from .cli.main import main
|
2
|
+
|
3
|
+
if __name__ == "__main__":
|
4
|
+
main()
|
5
|
+
|
janito/_version.py
CHANGED
@@ -1,58 +1,58 @@
|
|
1
|
-
"""Version handling for Janito.
|
2
|
-
Attempts to obtain the package version in the following order:
|
3
|
-
1. If a janito.version module exists (generated when the package is built with
|
4
|
-
setuptools-scm), use the version attribute from that module.
|
5
|
-
2. Ask importlib.metadata for the installed distribution version – works for
|
6
|
-
both regular and editable installs handled by pip.
|
7
|
-
3. Fall back to calling setuptools_scm.get_version() directly, using the git
|
8
|
-
repository when running from source without an installed distribution.
|
9
|
-
4. If everything else fails, return the literal string ``"unknown"`` so that
|
10
|
-
the application continues to work even when the version cannot be
|
11
|
-
determined.
|
12
|
-
|
13
|
-
This layered approach guarantees that a meaningful version string is returned
|
14
|
-
in most development and production scenarios while keeping Janito free from
|
15
|
-
hard-coded version numbers.
|
16
|
-
"""
|
17
|
-
|
18
|
-
from __future__ import annotations
|
19
|
-
|
20
|
-
import pathlib
|
21
|
-
from importlib import metadata as importlib_metadata
|
22
|
-
|
23
|
-
__all__ = ["__version__"]
|
24
|
-
|
25
|
-
|
26
|
-
# 1. "janito.version" (generated at build time by setuptools-scm)
|
27
|
-
try:
|
28
|
-
from . import version as _generated_version # type: ignore
|
29
|
-
|
30
|
-
__version__: str = _generated_version.version # pytype: disable=module-attr
|
31
|
-
except ImportError: # pragma: no cover – not available in editable installs
|
32
|
-
|
33
|
-
def _resolve_version() -> str:
|
34
|
-
"""Resolve the version string using several fallbacks."""
|
35
|
-
|
36
|
-
# 2. importlib.metadata – works for both regular and `pip install -e`.
|
37
|
-
try:
|
38
|
-
return importlib_metadata.version("janito")
|
39
|
-
except importlib_metadata.PackageNotFoundError:
|
40
|
-
pass # Not installed – probably running from a source checkout.
|
41
|
-
|
42
|
-
# 3. setuptools_scm – query the VCS metadata directly.
|
43
|
-
try:
|
44
|
-
from setuptools_scm import get_version # Imported lazily.
|
45
|
-
|
46
|
-
package_root = pathlib.Path(__file__).resolve().parent.parent
|
47
|
-
return get_version(root=str(package_root), relative_to=__file__)
|
48
|
-
except Exception: # pragma: no cover – any failure here falls through
|
49
|
-
# Either setuptools_scm is not available or this is not a git repo.
|
50
|
-
pass
|
51
|
-
|
52
|
-
# 4. Ultimate fallback – return a placeholder.
|
53
|
-
return "unknown"
|
54
|
-
|
55
|
-
__version__ = _resolve_version()
|
56
|
-
|
57
|
-
|
58
|
-
|
1
|
+
"""Version handling for Janito.
|
2
|
+
Attempts to obtain the package version in the following order:
|
3
|
+
1. If a janito.version module exists (generated when the package is built with
|
4
|
+
setuptools-scm), use the version attribute from that module.
|
5
|
+
2. Ask importlib.metadata for the installed distribution version – works for
|
6
|
+
both regular and editable installs handled by pip.
|
7
|
+
3. Fall back to calling setuptools_scm.get_version() directly, using the git
|
8
|
+
repository when running from source without an installed distribution.
|
9
|
+
4. If everything else fails, return the literal string ``"unknown"`` so that
|
10
|
+
the application continues to work even when the version cannot be
|
11
|
+
determined.
|
12
|
+
|
13
|
+
This layered approach guarantees that a meaningful version string is returned
|
14
|
+
in most development and production scenarios while keeping Janito free from
|
15
|
+
hard-coded version numbers.
|
16
|
+
"""
|
17
|
+
|
18
|
+
from __future__ import annotations
|
19
|
+
|
20
|
+
import pathlib
|
21
|
+
from importlib import metadata as importlib_metadata
|
22
|
+
|
23
|
+
__all__ = ["__version__"]
|
24
|
+
|
25
|
+
|
26
|
+
# 1. "janito.version" (generated at build time by setuptools-scm)
|
27
|
+
try:
|
28
|
+
from . import version as _generated_version # type: ignore
|
29
|
+
|
30
|
+
__version__: str = _generated_version.version # pytype: disable=module-attr
|
31
|
+
except ImportError: # pragma: no cover – not available in editable installs
|
32
|
+
|
33
|
+
def _resolve_version() -> str:
|
34
|
+
"""Resolve the version string using several fallbacks."""
|
35
|
+
|
36
|
+
# 2. importlib.metadata – works for both regular and `pip install -e`.
|
37
|
+
try:
|
38
|
+
return importlib_metadata.version("janito")
|
39
|
+
except importlib_metadata.PackageNotFoundError:
|
40
|
+
pass # Not installed – probably running from a source checkout.
|
41
|
+
|
42
|
+
# 3. setuptools_scm – query the VCS metadata directly.
|
43
|
+
try:
|
44
|
+
from setuptools_scm import get_version # Imported lazily.
|
45
|
+
|
46
|
+
package_root = pathlib.Path(__file__).resolve().parent.parent
|
47
|
+
return get_version(root=str(package_root), relative_to=__file__)
|
48
|
+
except Exception: # pragma: no cover – any failure here falls through
|
49
|
+
# Either setuptools_scm is not available or this is not a git repo.
|
50
|
+
pass
|
51
|
+
|
52
|
+
# 4. Ultimate fallback – return a placeholder.
|
53
|
+
return "unknown"
|
54
|
+
|
55
|
+
__version__ = _resolve_version()
|
56
|
+
|
57
|
+
|
58
|
+
|
janito/agent/setup_agent.py
CHANGED
@@ -1,241 +1,241 @@
|
|
1
|
-
import importlib.resources
|
2
|
-
import re
|
3
|
-
import os
|
4
|
-
import sys
|
5
|
-
import time
|
6
|
-
import warnings
|
7
|
-
import threading
|
8
|
-
from pathlib import Path
|
9
|
-
from jinja2 import Template
|
10
|
-
from pathlib import Path
|
11
|
-
from queue import Queue
|
12
|
-
from rich import print as rich_print
|
13
|
-
from janito.tools import get_local_tools_adapter
|
14
|
-
from janito.llm.agent import LLMAgent
|
15
|
-
from janito.drivers.driver_registry import get_driver_class
|
16
|
-
from janito.platform_discovery import PlatformDiscovery
|
17
|
-
from janito.tools.tool_base import ToolPermissions
|
18
|
-
from janito.tools.permissions import get_global_allowed_permissions
|
19
|
-
|
20
|
-
def _load_template_content(profile, templates_dir):
|
21
|
-
"""
|
22
|
-
Loads the template content for the given profile from the specified directory or package resources.
|
23
|
-
If the profile template is not found in the default locations, tries to load from the user profiles directory ~/.janito/profiles.
|
24
|
-
"""
|
25
|
-
|
26
|
-
|
27
|
-
template_filename = f"system_prompt_template_{profile}.txt.j2"
|
28
|
-
template_path = templates_dir / template_filename
|
29
|
-
if template_path.exists():
|
30
|
-
with open(template_path, "r", encoding="utf-8") as file:
|
31
|
-
return file.read(), template_path
|
32
|
-
# Try package import fallback
|
33
|
-
try:
|
34
|
-
with importlib.resources.files("janito.agent.templates.profiles").joinpath(
|
35
|
-
template_filename
|
36
|
-
).open("r", encoding="utf-8") as file:
|
37
|
-
return file.read(), template_path
|
38
|
-
except (FileNotFoundError, ModuleNotFoundError, AttributeError):
|
39
|
-
# Try user profiles directory
|
40
|
-
user_profiles_dir = Path(os.path.expanduser("~/.janito/profiles"))
|
41
|
-
user_template_path = user_profiles_dir / profile
|
42
|
-
if user_template_path.exists():
|
43
|
-
with open(user_template_path, "r", encoding="utf-8") as file:
|
44
|
-
return file.read(), user_template_path
|
45
|
-
raise FileNotFoundError(
|
46
|
-
f"[janito] Could not find profile-specific template '{template_filename}' in {template_path} nor in janito.agent.templates.profiles package nor in user profiles directory {user_template_path}."
|
47
|
-
)
|
48
|
-
|
49
|
-
|
50
|
-
def _prepare_template_context(role, profile, allowed_permissions):
|
51
|
-
"""
|
52
|
-
Prepares the context dictionary for Jinja2 template rendering.
|
53
|
-
"""
|
54
|
-
context = {}
|
55
|
-
context["role"] = role or "developer"
|
56
|
-
context["profile"] = profile
|
57
|
-
if allowed_permissions is None:
|
58
|
-
allowed_permissions = get_global_allowed_permissions()
|
59
|
-
# Convert ToolPermissions -> string like "rwx"
|
60
|
-
if isinstance(allowed_permissions, ToolPermissions):
|
61
|
-
perm_str = ""
|
62
|
-
if allowed_permissions.read:
|
63
|
-
perm_str += "r"
|
64
|
-
if allowed_permissions.write:
|
65
|
-
perm_str += "w"
|
66
|
-
if allowed_permissions.execute:
|
67
|
-
perm_str += "x"
|
68
|
-
allowed_permissions = perm_str or None
|
69
|
-
context["allowed_permissions"] = allowed_permissions
|
70
|
-
# Inject platform info if execute permission is present
|
71
|
-
if allowed_permissions and 'x' in allowed_permissions:
|
72
|
-
pd = PlatformDiscovery()
|
73
|
-
context["platform"] = pd.get_platform_name()
|
74
|
-
context["python_version"] = pd.get_python_version()
|
75
|
-
context["shell_info"] = pd.detect_shell()
|
76
|
-
return context
|
77
|
-
|
78
|
-
|
79
|
-
def _create_agent(provider_instance, tools_provider, role, system_prompt, input_queue, output_queue, verbose_agent, context, template_path, profile):
|
80
|
-
"""
|
81
|
-
Creates and returns an LLMAgent instance with the provided parameters.
|
82
|
-
"""
|
83
|
-
agent = LLMAgent(
|
84
|
-
provider_instance,
|
85
|
-
tools_provider,
|
86
|
-
agent_name=role or "developer",
|
87
|
-
system_prompt=system_prompt,
|
88
|
-
input_queue=input_queue,
|
89
|
-
output_queue=output_queue,
|
90
|
-
verbose_agent=verbose_agent,
|
91
|
-
)
|
92
|
-
agent.template_vars["role"] = context["role"]
|
93
|
-
agent.template_vars["profile"] = profile
|
94
|
-
agent.system_prompt_template = str(template_path)
|
95
|
-
agent._template_vars = context.copy()
|
96
|
-
agent._original_template_vars = context.copy()
|
97
|
-
return agent
|
98
|
-
|
99
|
-
|
100
|
-
def setup_agent(
|
101
|
-
provider_instance,
|
102
|
-
llm_driver_config,
|
103
|
-
role=None,
|
104
|
-
templates_dir=None,
|
105
|
-
zero_mode=False,
|
106
|
-
input_queue=None,
|
107
|
-
output_queue=None,
|
108
|
-
verbose_tools=False,
|
109
|
-
verbose_agent=False,
|
110
|
-
allowed_permissions=None,
|
111
|
-
profile=None,
|
112
|
-
profile_system_prompt=None,
|
113
|
-
):
|
114
|
-
"""
|
115
|
-
Creates an agent. A system prompt is rendered from a template only when a profile is specified.
|
116
|
-
"""
|
117
|
-
tools_provider = get_local_tools_adapter()
|
118
|
-
tools_provider.set_verbose_tools(verbose_tools)
|
119
|
-
|
120
|
-
# If zero_mode is enabled or no profile is given we skip the system prompt.
|
121
|
-
if zero_mode or (profile is None and profile_system_prompt is None):
|
122
|
-
agent = LLMAgent(
|
123
|
-
provider_instance,
|
124
|
-
tools_provider,
|
125
|
-
agent_name=role or "developer",
|
126
|
-
system_prompt=None,
|
127
|
-
input_queue=input_queue,
|
128
|
-
output_queue=output_queue,
|
129
|
-
verbose_agent=verbose_agent,
|
130
|
-
)
|
131
|
-
if role:
|
132
|
-
agent.template_vars["role"] = role
|
133
|
-
return agent
|
134
|
-
|
135
|
-
# If profile_system_prompt is set, use it directly
|
136
|
-
if profile_system_prompt is not None:
|
137
|
-
agent = LLMAgent(
|
138
|
-
provider_instance,
|
139
|
-
tools_provider,
|
140
|
-
agent_name=role or "developer",
|
141
|
-
system_prompt=profile_system_prompt,
|
142
|
-
input_queue=input_queue,
|
143
|
-
output_queue=output_queue,
|
144
|
-
verbose_agent=verbose_agent,
|
145
|
-
)
|
146
|
-
agent.template_vars["role"] = role or "developer"
|
147
|
-
agent.template_vars["profile"] = None
|
148
|
-
agent.template_vars["profile_system_prompt"] = profile_system_prompt
|
149
|
-
return agent
|
150
|
-
|
151
|
-
# Normal flow (profile-specific system prompt)
|
152
|
-
if templates_dir is None:
|
153
|
-
templates_dir = Path(__file__).parent / "templates" / "profiles"
|
154
|
-
template_content, template_path = _load_template_content(profile, templates_dir)
|
155
|
-
|
156
|
-
template = Template(template_content)
|
157
|
-
context = _prepare_template_context(role, profile, allowed_permissions)
|
158
|
-
|
159
|
-
# Debug output if requested
|
160
|
-
debug_flag = False
|
161
|
-
try:
|
162
|
-
debug_flag = (hasattr(sys, 'argv') and ('--debug' in sys.argv or '--verbose' in sys.argv or '-v' in sys.argv))
|
163
|
-
except Exception:
|
164
|
-
pass
|
165
|
-
if debug_flag:
|
166
|
-
rich_print(f"[bold magenta][DEBUG][/bold magenta] Rendering system prompt template '[cyan]{template_path.name}[/cyan]' with allowed_permissions: [yellow]{context.get('allowed_permissions')}[/yellow]")
|
167
|
-
rich_print(f"[bold magenta][DEBUG][/bold magenta] Template context: [green]{context}[/green]")
|
168
|
-
start_render = time.time()
|
169
|
-
rendered_prompt = template.render(**context)
|
170
|
-
end_render = time.time()
|
171
|
-
# Merge multiple empty lines into a single empty line
|
172
|
-
rendered_prompt = re.sub(r'\n{3,}', '\n\n', rendered_prompt)
|
173
|
-
|
174
|
-
return _create_agent(
|
175
|
-
provider_instance,
|
176
|
-
tools_provider,
|
177
|
-
role,
|
178
|
-
rendered_prompt,
|
179
|
-
input_queue,
|
180
|
-
output_queue,
|
181
|
-
verbose_agent,
|
182
|
-
context,
|
183
|
-
template_path,
|
184
|
-
profile,
|
185
|
-
)
|
186
|
-
|
187
|
-
|
188
|
-
def create_configured_agent(
|
189
|
-
*,
|
190
|
-
provider_instance=None,
|
191
|
-
llm_driver_config=None,
|
192
|
-
role=None,
|
193
|
-
verbose_tools=False,
|
194
|
-
verbose_agent=False,
|
195
|
-
templates_dir=None,
|
196
|
-
zero_mode=False,
|
197
|
-
allowed_permissions=None,
|
198
|
-
profile=None,
|
199
|
-
profile_system_prompt=None,
|
200
|
-
):
|
201
|
-
"""
|
202
|
-
Normalizes agent setup for all CLI modes.
|
203
|
-
|
204
|
-
Args:
|
205
|
-
provider_instance: Provider instance for the agent
|
206
|
-
llm_driver_config: LLM driver configuration
|
207
|
-
role: Optional role string
|
208
|
-
verbose_tools: Optional, default False
|
209
|
-
verbose_agent: Optional, default False
|
210
|
-
templates_dir: Optional
|
211
|
-
zero_mode: Optional, default False
|
212
|
-
|
213
|
-
Returns:
|
214
|
-
Configured agent instance
|
215
|
-
"""
|
216
|
-
input_queue = None
|
217
|
-
output_queue = None
|
218
|
-
driver = None
|
219
|
-
if hasattr(provider_instance, "create_driver"):
|
220
|
-
driver = provider_instance.create_driver()
|
221
|
-
driver.start() # Ensure the driver background thread is started
|
222
|
-
input_queue = getattr(driver, "input_queue", None)
|
223
|
-
output_queue = getattr(driver, "output_queue", None)
|
224
|
-
|
225
|
-
agent = setup_agent(
|
226
|
-
provider_instance=provider_instance,
|
227
|
-
llm_driver_config=llm_driver_config,
|
228
|
-
role=role,
|
229
|
-
templates_dir=templates_dir,
|
230
|
-
zero_mode=zero_mode,
|
231
|
-
input_queue=input_queue,
|
232
|
-
output_queue=output_queue,
|
233
|
-
verbose_tools=verbose_tools,
|
234
|
-
verbose_agent=verbose_agent,
|
235
|
-
allowed_permissions=allowed_permissions,
|
236
|
-
profile=profile,
|
237
|
-
profile_system_prompt=profile_system_prompt,
|
238
|
-
)
|
239
|
-
if driver is not None:
|
240
|
-
agent.driver = driver # Attach driver to agent for thread management
|
1
|
+
import importlib.resources
|
2
|
+
import re
|
3
|
+
import os
|
4
|
+
import sys
|
5
|
+
import time
|
6
|
+
import warnings
|
7
|
+
import threading
|
8
|
+
from pathlib import Path
|
9
|
+
from jinja2 import Template
|
10
|
+
from pathlib import Path
|
11
|
+
from queue import Queue
|
12
|
+
from rich import print as rich_print
|
13
|
+
from janito.tools import get_local_tools_adapter
|
14
|
+
from janito.llm.agent import LLMAgent
|
15
|
+
from janito.drivers.driver_registry import get_driver_class
|
16
|
+
from janito.platform_discovery import PlatformDiscovery
|
17
|
+
from janito.tools.tool_base import ToolPermissions
|
18
|
+
from janito.tools.permissions import get_global_allowed_permissions
|
19
|
+
|
20
|
+
def _load_template_content(profile, templates_dir):
|
21
|
+
"""
|
22
|
+
Loads the template content for the given profile from the specified directory or package resources.
|
23
|
+
If the profile template is not found in the default locations, tries to load from the user profiles directory ~/.janito/profiles.
|
24
|
+
"""
|
25
|
+
|
26
|
+
|
27
|
+
template_filename = f"system_prompt_template_{profile}.txt.j2"
|
28
|
+
template_path = templates_dir / template_filename
|
29
|
+
if template_path.exists():
|
30
|
+
with open(template_path, "r", encoding="utf-8") as file:
|
31
|
+
return file.read(), template_path
|
32
|
+
# Try package import fallback
|
33
|
+
try:
|
34
|
+
with importlib.resources.files("janito.agent.templates.profiles").joinpath(
|
35
|
+
template_filename
|
36
|
+
).open("r", encoding="utf-8") as file:
|
37
|
+
return file.read(), template_path
|
38
|
+
except (FileNotFoundError, ModuleNotFoundError, AttributeError):
|
39
|
+
# Try user profiles directory
|
40
|
+
user_profiles_dir = Path(os.path.expanduser("~/.janito/profiles"))
|
41
|
+
user_template_path = user_profiles_dir / profile
|
42
|
+
if user_template_path.exists():
|
43
|
+
with open(user_template_path, "r", encoding="utf-8") as file:
|
44
|
+
return file.read(), user_template_path
|
45
|
+
raise FileNotFoundError(
|
46
|
+
f"[janito] Could not find profile-specific template '{template_filename}' in {template_path} nor in janito.agent.templates.profiles package nor in user profiles directory {user_template_path}."
|
47
|
+
)
|
48
|
+
|
49
|
+
|
50
|
+
def _prepare_template_context(role, profile, allowed_permissions):
|
51
|
+
"""
|
52
|
+
Prepares the context dictionary for Jinja2 template rendering.
|
53
|
+
"""
|
54
|
+
context = {}
|
55
|
+
context["role"] = role or "developer"
|
56
|
+
context["profile"] = profile
|
57
|
+
if allowed_permissions is None:
|
58
|
+
allowed_permissions = get_global_allowed_permissions()
|
59
|
+
# Convert ToolPermissions -> string like "rwx"
|
60
|
+
if isinstance(allowed_permissions, ToolPermissions):
|
61
|
+
perm_str = ""
|
62
|
+
if allowed_permissions.read:
|
63
|
+
perm_str += "r"
|
64
|
+
if allowed_permissions.write:
|
65
|
+
perm_str += "w"
|
66
|
+
if allowed_permissions.execute:
|
67
|
+
perm_str += "x"
|
68
|
+
allowed_permissions = perm_str or None
|
69
|
+
context["allowed_permissions"] = allowed_permissions
|
70
|
+
# Inject platform info if execute permission is present
|
71
|
+
if allowed_permissions and 'x' in allowed_permissions:
|
72
|
+
pd = PlatformDiscovery()
|
73
|
+
context["platform"] = pd.get_platform_name()
|
74
|
+
context["python_version"] = pd.get_python_version()
|
75
|
+
context["shell_info"] = pd.detect_shell()
|
76
|
+
return context
|
77
|
+
|
78
|
+
|
79
|
+
def _create_agent(provider_instance, tools_provider, role, system_prompt, input_queue, output_queue, verbose_agent, context, template_path, profile):
|
80
|
+
"""
|
81
|
+
Creates and returns an LLMAgent instance with the provided parameters.
|
82
|
+
"""
|
83
|
+
agent = LLMAgent(
|
84
|
+
provider_instance,
|
85
|
+
tools_provider,
|
86
|
+
agent_name=role or "developer",
|
87
|
+
system_prompt=system_prompt,
|
88
|
+
input_queue=input_queue,
|
89
|
+
output_queue=output_queue,
|
90
|
+
verbose_agent=verbose_agent,
|
91
|
+
)
|
92
|
+
agent.template_vars["role"] = context["role"]
|
93
|
+
agent.template_vars["profile"] = profile
|
94
|
+
agent.system_prompt_template = str(template_path)
|
95
|
+
agent._template_vars = context.copy()
|
96
|
+
agent._original_template_vars = context.copy()
|
97
|
+
return agent
|
98
|
+
|
99
|
+
|
100
|
+
def setup_agent(
|
101
|
+
provider_instance,
|
102
|
+
llm_driver_config,
|
103
|
+
role=None,
|
104
|
+
templates_dir=None,
|
105
|
+
zero_mode=False,
|
106
|
+
input_queue=None,
|
107
|
+
output_queue=None,
|
108
|
+
verbose_tools=False,
|
109
|
+
verbose_agent=False,
|
110
|
+
allowed_permissions=None,
|
111
|
+
profile=None,
|
112
|
+
profile_system_prompt=None,
|
113
|
+
):
|
114
|
+
"""
|
115
|
+
Creates an agent. A system prompt is rendered from a template only when a profile is specified.
|
116
|
+
"""
|
117
|
+
tools_provider = get_local_tools_adapter()
|
118
|
+
tools_provider.set_verbose_tools(verbose_tools)
|
119
|
+
|
120
|
+
# If zero_mode is enabled or no profile is given we skip the system prompt.
|
121
|
+
if zero_mode or (profile is None and profile_system_prompt is None):
|
122
|
+
agent = LLMAgent(
|
123
|
+
provider_instance,
|
124
|
+
tools_provider,
|
125
|
+
agent_name=role or "developer",
|
126
|
+
system_prompt=None,
|
127
|
+
input_queue=input_queue,
|
128
|
+
output_queue=output_queue,
|
129
|
+
verbose_agent=verbose_agent,
|
130
|
+
)
|
131
|
+
if role:
|
132
|
+
agent.template_vars["role"] = role
|
133
|
+
return agent
|
134
|
+
|
135
|
+
# If profile_system_prompt is set, use it directly
|
136
|
+
if profile_system_prompt is not None:
|
137
|
+
agent = LLMAgent(
|
138
|
+
provider_instance,
|
139
|
+
tools_provider,
|
140
|
+
agent_name=role or "developer",
|
141
|
+
system_prompt=profile_system_prompt,
|
142
|
+
input_queue=input_queue,
|
143
|
+
output_queue=output_queue,
|
144
|
+
verbose_agent=verbose_agent,
|
145
|
+
)
|
146
|
+
agent.template_vars["role"] = role or "developer"
|
147
|
+
agent.template_vars["profile"] = None
|
148
|
+
agent.template_vars["profile_system_prompt"] = profile_system_prompt
|
149
|
+
return agent
|
150
|
+
|
151
|
+
# Normal flow (profile-specific system prompt)
|
152
|
+
if templates_dir is None:
|
153
|
+
templates_dir = Path(__file__).parent / "templates" / "profiles"
|
154
|
+
template_content, template_path = _load_template_content(profile, templates_dir)
|
155
|
+
|
156
|
+
template = Template(template_content)
|
157
|
+
context = _prepare_template_context(role, profile, allowed_permissions)
|
158
|
+
|
159
|
+
# Debug output if requested
|
160
|
+
debug_flag = False
|
161
|
+
try:
|
162
|
+
debug_flag = (hasattr(sys, 'argv') and ('--debug' in sys.argv or '--verbose' in sys.argv or '-v' in sys.argv))
|
163
|
+
except Exception:
|
164
|
+
pass
|
165
|
+
if debug_flag:
|
166
|
+
rich_print(f"[bold magenta][DEBUG][/bold magenta] Rendering system prompt template '[cyan]{template_path.name}[/cyan]' with allowed_permissions: [yellow]{context.get('allowed_permissions')}[/yellow]")
|
167
|
+
rich_print(f"[bold magenta][DEBUG][/bold magenta] Template context: [green]{context}[/green]")
|
168
|
+
start_render = time.time()
|
169
|
+
rendered_prompt = template.render(**context)
|
170
|
+
end_render = time.time()
|
171
|
+
# Merge multiple empty lines into a single empty line
|
172
|
+
rendered_prompt = re.sub(r'\n{3,}', '\n\n', rendered_prompt)
|
173
|
+
|
174
|
+
return _create_agent(
|
175
|
+
provider_instance,
|
176
|
+
tools_provider,
|
177
|
+
role,
|
178
|
+
rendered_prompt,
|
179
|
+
input_queue,
|
180
|
+
output_queue,
|
181
|
+
verbose_agent,
|
182
|
+
context,
|
183
|
+
template_path,
|
184
|
+
profile,
|
185
|
+
)
|
186
|
+
|
187
|
+
|
188
|
+
def create_configured_agent(
|
189
|
+
*,
|
190
|
+
provider_instance=None,
|
191
|
+
llm_driver_config=None,
|
192
|
+
role=None,
|
193
|
+
verbose_tools=False,
|
194
|
+
verbose_agent=False,
|
195
|
+
templates_dir=None,
|
196
|
+
zero_mode=False,
|
197
|
+
allowed_permissions=None,
|
198
|
+
profile=None,
|
199
|
+
profile_system_prompt=None,
|
200
|
+
):
|
201
|
+
"""
|
202
|
+
Normalizes agent setup for all CLI modes.
|
203
|
+
|
204
|
+
Args:
|
205
|
+
provider_instance: Provider instance for the agent
|
206
|
+
llm_driver_config: LLM driver configuration
|
207
|
+
role: Optional role string
|
208
|
+
verbose_tools: Optional, default False
|
209
|
+
verbose_agent: Optional, default False
|
210
|
+
templates_dir: Optional
|
211
|
+
zero_mode: Optional, default False
|
212
|
+
|
213
|
+
Returns:
|
214
|
+
Configured agent instance
|
215
|
+
"""
|
216
|
+
input_queue = None
|
217
|
+
output_queue = None
|
218
|
+
driver = None
|
219
|
+
if hasattr(provider_instance, "create_driver"):
|
220
|
+
driver = provider_instance.create_driver()
|
221
|
+
driver.start() # Ensure the driver background thread is started
|
222
|
+
input_queue = getattr(driver, "input_queue", None)
|
223
|
+
output_queue = getattr(driver, "output_queue", None)
|
224
|
+
|
225
|
+
agent = setup_agent(
|
226
|
+
provider_instance=provider_instance,
|
227
|
+
llm_driver_config=llm_driver_config,
|
228
|
+
role=role,
|
229
|
+
templates_dir=templates_dir,
|
230
|
+
zero_mode=zero_mode,
|
231
|
+
input_queue=input_queue,
|
232
|
+
output_queue=output_queue,
|
233
|
+
verbose_tools=verbose_tools,
|
234
|
+
verbose_agent=verbose_agent,
|
235
|
+
allowed_permissions=allowed_permissions,
|
236
|
+
profile=profile,
|
237
|
+
profile_system_prompt=profile_system_prompt,
|
238
|
+
)
|
239
|
+
if driver is not None:
|
240
|
+
agent.driver = driver # Attach driver to agent for thread management
|
241
241
|
return agent
|