janito 2.4.0__tar.gz → 2.5.1__tar.gz
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-2.5.1/.vscode/settings.json +19 -0
- janito-2.5.1/CHANGELOG.md +103 -0
- {janito-2.4.0 → janito-2.5.1}/PKG-INFO +2 -15
- {janito-2.4.0 → janito-2.5.1}/README.md +1 -14
- janito-2.5.1/adding_mcp.txt +138 -0
- {janito-2.4.0 → janito-2.5.1}/janito/agent/setup_agent.py +4 -3
- janito-2.5.1/janito/agent/templates/profiles/system_prompt_template_assistant.txt.j2 +1 -0
- janito-2.5.1/janito/cli/chat_mode/script_runner.py +153 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/session.py +56 -36
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/session_profile_select.py +1 -1
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/__init__.py +6 -2
- janito-2.5.1/janito/cli/chat_mode/shell/commands/bang.py +36 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/conversation_restart.py +4 -28
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/execute.py +1 -2
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/help.py +1 -1
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/prompt.py +1 -16
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/read.py +1 -2
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/role.py +2 -9
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/write.py +1 -2
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/input_history.py +1 -1
- janito-2.5.1/janito/cli/chat_mode/shell/session/manager.py +42 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/core/runner.py +4 -4
- {janito-2.4.0 → janito-2.5.1}/janito/cli/main_cli.py +12 -5
- {janito-2.4.0 → janito-2.5.1}/janito/cli/prompt_setup.py +2 -2
- {janito-2.4.0 → janito-2.5.1}/janito/cli/rich_terminal_reporter.py +21 -6
- {janito-2.4.0 → janito-2.5.1}/janito/cli/single_shot_mode/handler.py +13 -7
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/driver_registry.py +0 -2
- {janito-2.4.0 → janito-2.5.1}/janito/formatting_token.py +7 -6
- {janito-2.4.0 → janito-2.5.1}/janito/llm/agent.py +1 -1
- {janito-2.4.0 → janito-2.5.1}/janito/provider_registry.py +1 -1
- {janito-2.4.0 → janito-2.5.1}/janito/providers/__init__.py +0 -2
- {janito-2.4.0 → janito-2.5.1}/janito/providers/provider_static_info.py +0 -3
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/core.py +1 -1
- {janito-2.4.0 → janito-2.5.1}/janito/tools/tool_base.py +0 -10
- {janito-2.4.0 → janito-2.5.1}/janito.egg-info/PKG-INFO +2 -15
- {janito-2.4.0 → janito-2.5.1}/janito.egg-info/SOURCES.txt +5 -4
- {janito-2.4.0 → janito-2.5.1}/pytest.ini +1 -0
- {janito-2.4.0 → janito-2.5.1}/tools/release.py +6 -0
- janito-2.4.0/CHANGELOG.md +0 -57
- janito-2.4.0/STRUCTURE.md +0 -14
- janito-2.4.0/TEST_STRATEGY.md +0 -0
- janito-2.4.0/benchmark/cli_basics.py +0 -4
- janito-2.4.0/janito/cli/chat_mode/shell/session/manager.py +0 -110
- janito-2.4.0/janito2.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/.codespellrc +0 -0
- {janito-2.4.0 → janito-2.5.1}/.github/workflows/python-app.yml +0 -0
- {janito-2.4.0 → janito-2.5.1}/.gitignore +0 -0
- {janito-2.4.0 → janito-2.5.1}/.pre-commit-config.yaml +0 -0
- {janito-2.4.0 → janito-2.5.1}/.secrets.baseline +0 -0
- {janito-2.4.0 → janito-2.5.1}/LICENSE +0 -0
- {janito-2.4.0 → janito-2.5.1}/PROVIDERS.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/README-dev.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/DIV.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/Interfaces.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/TOOLBAR-STYLING.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/about/costs.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/about/vs-webchats.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/about/why.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/alternatives.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/code_intelligence/agentic-frameworks-comparison.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/code_intelligence/code-generation-challenges.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/code_intelligence/code-generation-observability.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/code_intelligence/our-approach.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/code_intelligence/why-string-replacement.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/concepts/analysis-style.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/concepts/index.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/concepts/language-model-clients.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/concepts/prompt-design-style.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/deepseek-setup.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/driver-flow.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/driver-request-cancellation.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/drivers/events.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/drivers.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/event-bus.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/configuration.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/developing.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/installation.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/profiles.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/prompting/README.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/single-shot-terminal.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/terminal-shell.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/tools-developer-guide.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/using.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/guides/using_tools.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/code-generation-observability.png +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/code_generation_observability.png +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/happy-programmer.png +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/happy-programmer.svg +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/terminal-one-shot.png +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/terminal-shell.png +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/terminal_one_shot.png +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/imgs/terminal_shell.png +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/index.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/llm-drivers-required-config.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/llm-drivers.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/meta/developer-toolchain.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/meta/quality-checks.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/reference/api.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/reference/azure-openai.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/reference/cli-options.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/reference/message-handler-model.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/reference/rich-message-handler.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/supported-providers-models.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/terms.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/tools-index.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/tools-natural-results.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/docs/tools-precision.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/__main__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/_version.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/bindings.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/chat_entry.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/prompt_style.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/autocomplete.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/_priv_check.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/base.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/clear.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/history_view.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/lang.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/livelogs.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/model.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/multi.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/session.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/session_control.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/tools.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/utility.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands/verbose.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/commands.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/session/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/session/history.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/shell/session.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/chat_mode/toolbar.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/list_models.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/list_providers.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/list_tools.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/model_selection.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/model_utils.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/set_api_key.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/show_config.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/cli_commands/show_system_prompt.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/config.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/console.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/core/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/core/event_logger.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/core/getters.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/core/setters.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/core/unsetters.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/main.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/prompt_core.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/prompt_handler.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/single_shot_mode/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/utils.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/cli/verbose_output.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/config.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/config_manager.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/conversation_history.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/dir_walk_utils.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/driver_events.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/anthropic/driver.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/azure_openai/driver.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/dashscope.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/mistralai/driver.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/openai/README.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/openai/driver.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/drivers/openai_responses.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/event_bus/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/event_bus/bus.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/event_bus/event.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/event_bus/handler.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/event_bus/queue_bus.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/exceptions.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/formatting.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/gitignore_utils.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/i18n/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/i18n/messages.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/i18n/pt.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/README.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/auth.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/driver.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/driver_config.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/driver_config_builder.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/driver_input.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/message_parts.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/model.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/llm/provider.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/perf_singleton.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/performance_collector.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/platform_discovery.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/provider_config.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/anthropic/model_info.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/anthropic/provider.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/azure_openai/model_info.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/azure_openai/provider.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/dashscope.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/deepseek/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/deepseek/model_info.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/deepseek/provider.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/google/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/google/model_info.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/google/provider.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/mistralai/model_info.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/mistralai/provider.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/openai/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/openai/model_info.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/openai/provider.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/openai/schema_generator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/providers/registry.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/report_events.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/shell.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/DOCSTRING_STANDARD.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/README.md +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/adapter.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/ask_user.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/copy_file.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/create_directory.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/create_file.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/delete_text_in_file.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/fetch_url.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/find_files.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/get_file_outline/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/get_file_outline/core.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/get_file_outline/java_outline.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/get_file_outline/markdown_outline.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/get_file_outline/python_outline.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/get_file_outline/python_outline_v2.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/get_file_outline/search_outline.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/move_file.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/open_html_in_browser.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/open_url.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/python_code_run.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/python_command_run.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/python_file_run.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/remove_directory.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/remove_file.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/replace_text_in_file.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/run_bash_command.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/run_powershell_command.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/search_text/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/search_text/core.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/search_text/match_lines.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/search_text/pattern_utils.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/search_text/traverse_directory.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/__init__.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/css_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/html_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/js_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/json_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/python_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/xml_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/adapters/local/view_file.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/inspect_registry.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/outline_file.bak.zip +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/permissions.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/permissions_parse.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/tool_events.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/tool_run_exception.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/tool_use_tracker.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/tool_utils.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/tools_adapter.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/tools/tools_schema.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito/utils.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito.egg-info/dependency_links.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito.egg-info/entry_points.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito.egg-info/requires.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/janito.egg-info/top_level.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/mkdocs.yml +0 -0
- {janito-2.4.0 → janito-2.5.1}/pyproject.toml +0 -0
- {janito-2.4.0 → janito-2.5.1}/requirements-dev.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/requirements.txt +0 -0
- {janito-2.4.0 → janito-2.5.1}/setup.cfg +0 -0
- {janito-2.4.0 → janito-2.5.1}/tests/adapters/local/get_file_outline/test_core_outline.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/tests/test_cli_list_models.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/tests/test_cli_list_providers.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/tests/test_cli_version.py +0 -0
- {janito-2.4.0 → janito-2.5.1}/tox.ini +0 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"files.exclude": {
|
3
|
+
"**/__pycache__": true,
|
4
|
+
"**/build": true,
|
5
|
+
"**/dist": true,
|
6
|
+
"**/.eggs": true,
|
7
|
+
"**/*.egg-info": true,
|
8
|
+
"**/.tox": true,
|
9
|
+
"**/.nox": true,
|
10
|
+
"**/.hypothesis": true,
|
11
|
+
"**/.pytest_cache": true,
|
12
|
+
"**/.mypy_cache": true,
|
13
|
+
"**/.pyre": true,
|
14
|
+
"**/.ipynb_checkpoints": true,
|
15
|
+
"**/.ruff_cache": true,
|
16
|
+
"**/.janito": true,
|
17
|
+
"**/site": true
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
## [2.5.0] - 2025-07-01
|
6
|
+
### Added
|
7
|
+
- Show working directory in chat mode startup message.
|
8
|
+
- Bang (`!`) shell command handler for direct shell access from the chat interface.
|
9
|
+
- Elapsed time reporting to token usage summary and improved terminal output styling.
|
10
|
+
- CLI support for reading prompt from stdin and suppressing token usage summary in non-interactive mode.
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
- Import `os` in help command handler for future extensibility.
|
14
|
+
- Refactored `ChatSession._chat_loop` to reduce complexity by extracting command and prompt handling methods.
|
15
|
+
- Refactored profile selection, removed `ProfileShellHandler`, and improved terminal reporter output for STDOUT/STDERR.
|
16
|
+
- Refactored to remove `exec_enabled` argument from agent and CLI setup; now uses `args.exec` directly.
|
17
|
+
- Improved terminal output: added `delete_current_line` to `RichTerminalReporter` for cleaner UI.
|
18
|
+
- Refactored and cleaned up: removed redundant import of `handle_command`, removed backup, structure, and test strategy files, and added `.vscode/settings.json` for VSCode excludes.
|
19
|
+
|
20
|
+
### Removed
|
21
|
+
- MistralAI provider and driver references and related files.
|
22
|
+
- Conversation history persistence and updated input history path.
|
23
|
+
|
24
|
+
### Documentation
|
25
|
+
- Removed inline web file viewer documentation from `README.md` for clarity and focus on core options.
|
26
|
+
|
27
|
+
## [2.4.0]
|
28
|
+
|
29
|
+
### Changed
|
30
|
+
- Refactored tool permission management: migrated to a permission-based model (read/write/execute), updated CLI and docs, removed legacy execution toggling.
|
31
|
+
- Enhanced tool permissions: tools are now grouped by permission, config supports tool_permissions, ask_user is read-only, and permissions are applied at startup.
|
32
|
+
- Refined permission and tool output messages in shell commands; improved tool listing by permission class in tools.py.
|
33
|
+
- Refactored agent and prompt handler setup, improved model switching, and enhanced user interrupt handling. Includes new /model shell command and fixes for provider registry ASCII fallback.
|
34
|
+
- Refactored agent system prompt and permissions logic, switched to profile-based template selection, removed unused templates, and added --profile CLI support.
|
35
|
+
- Refactored chat mode startup messages and permission reset handling for improved clarity.
|
36
|
+
- Refactored ChatSession and ChatShellState: removed allow_execution logic and related assignments, use exec_enabled directly for execution control.
|
37
|
+
- Refactored tool system to use latest git tag for version detection in release script.
|
38
|
+
- Refined release script to recommend creating a new git tag if version exists on PyPI.
|
39
|
+
- Removed termweb: web file viewer and related CLI/editor features, updated docs and config accordingly.
|
40
|
+
- Removed temporary file x.txt.
|
41
|
+
- Restored tool permissions to CLI defaults on /restart; store and retrieve default tool permissions in AllowedPermissionsState. Runner now sets and saves default permissions for restoration. Updated conversation_restart to restore or fallback to all-off permissions.
|
42
|
+
- Updated disabled execution tools message for clarity.
|
43
|
+
- Docs and UX: clarified permissions (read/write/exec), added profiles doc links, and removed localhost references from UI/toolbar.
|
44
|
+
|
45
|
+
### Added
|
46
|
+
- Agent/driver: drain driver's input queue before sending new messages in chat() to prevent stale DriverInput processing.
|
47
|
+
|
48
|
+
### Fixed
|
49
|
+
- Ensure tools adapter is always available in provider classes, even if driver is missing. Prevents AttributeError in generic code paths relying on execute_tool().
|
50
|
+
|
51
|
+
## [2.3.1] - 2025-06-25
|
52
|
+
### Changed
|
53
|
+
- Bumped version to 2.3.1 in `version.py`, `pyproject.toml`, and `__init__.py`.
|
54
|
+
|
55
|
+
## [2.3.0] - 2025-06-25
|
56
|
+
### Added
|
57
|
+
- requirements-dev.txt with development dependencies (pytest, pre-commit, ruff, detect-secrets, codespell, black) for code quality and testing
|
58
|
+
- Java outline support to get_file_outline tool, including package-private methods
|
59
|
+
- create_driver method to AzureOpenAIProvider for driver instantiation
|
60
|
+
- CLI --version test and suppress pytest-asyncio deprecation warning
|
61
|
+
- New dependencies: prompt_toolkit, lxml, requests, bs4 to requirements.txt
|
62
|
+
|
63
|
+
### Changed
|
64
|
+
- Improved error messages and documentation
|
65
|
+
- Refined error handling in open_html_in_browser.py and open_url.py
|
66
|
+
- Refactor remove_file tool: use ReportAction.DELETE for all file removal actions
|
67
|
+
- Remove redundant _prepare_api_kwargs override in AzureOpenAIModelDriver
|
68
|
+
- Refactor(azure_openai): use 'model' directly in API kwargs, remove deployment_name remapping
|
69
|
+
- Add public read-only driver_config property to AzureOpenAIProvider
|
70
|
+
- Add _prepare_api_kwargs to support deployment_name for Azure OpenAI API compatibility
|
71
|
+
- Update toolbar bindings: add CTRL-C for interrupt/exit, clarify F1 usage
|
72
|
+
- Update pyproject.toml optional-dependencies section for setuptools compatibility
|
73
|
+
- Remove references to max_results in FindFilesTool docstring
|
74
|
+
- Refactor: use .jsonl extension for input history files instead of .log
|
75
|
+
- Refactor get_file_outline core logic to remove duplication and add tests
|
76
|
+
- Test CLI: Ensure error on missing provider and validate supported models output for each provider
|
77
|
+
- Configure dynamic dependencies in pyproject.toml
|
78
|
+
- Define dependencies in requirements.txt: attrs, rich, pathspec, setuptools, pyyaml, jinja2
|
79
|
+
- Add workdir support to LocalToolsAdapter and CLI; improve Python tool adapters
|
80
|
+
- Friendly error message when the provider is not present from the available ones
|
81
|
+
|
82
|
+
### Fixed
|
83
|
+
- Ensure error on missing provider and validate supported models output for each provider
|
84
|
+
- Update supported models table; remove o4-mini-high model from code and docs
|
85
|
+
|
86
|
+
## [2.1.1] - 2024-06-23
|
87
|
+
### Changed
|
88
|
+
- Bumped version to 2.1.1 in `version.py`, `pyproject.toml`, and `__init__.py`.
|
89
|
+
- docs: add DeepSeek setup guide, update navigation and references
|
90
|
+
- Add docs/deepseek-setup.md with setup instructions for DeepSeek provider
|
91
|
+
- Link DeepSeek setup in docs/index.md and mkdocs.yml navigation
|
92
|
+
- Fix model name: change 'deepseek-coder' to 'deepseek-reasoner' in DeepSeek provider and model_info
|
93
|
+
- Update DeepSeek provider docstrings and options to match supported models
|
94
|
+
|
95
|
+
## [2.1.0] - 2024-06-09
|
96
|
+
### Added
|
97
|
+
|
98
|
+
### Changed
|
99
|
+
- Bumped version to 2.1.0 in `version.py`, `pyproject.toml`, and `__init__.py`.
|
100
|
+
|
101
|
+
---
|
102
|
+
|
103
|
+
*Older changes may not be listed.*
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: janito
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.5.1
|
4
4
|
Summary: A new Python package called janito.
|
5
5
|
Author-email: João Pinto <lamego.pinto@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/janito-dev/janito
|
@@ -167,19 +167,6 @@ Janito has configuration options, like `--set api-key API_KEY` and `--set provid
|
|
167
167
|
|
168
168
|
### Advanced Options
|
169
169
|
|
170
|
-
- **Enable Inline Web File Viewer for Clickable Links**
|
171
|
-
|
172
|
-
By default, Janito can open referenced files in a browser-based viewer when you click on file links in supported terminals. To enable this feature for your session, use the `--web` flag:
|
173
|
-
|
174
|
-
```bash
|
175
|
-
janito --web
|
176
|
-
```
|
177
|
-
|
178
|
-
This starts the lightweight web file viewer () in the background, allowing you to inspect files referenced in responses directly in your browser. Combine with interactive mode or prompts as needed.
|
179
|
-
|
180
|
-
> **Tip:** Use with the interactive shell for the best experience with clickable file links.
|
181
|
-
|
182
|
-
|
183
170
|
- **Enable Execution Tools (Code/Shell Execution)**
|
184
171
|
|
185
172
|
By default, **all tool privileges (read, write, execute)** are disabled for safety. This means Janito starts with no permissions to run tools that read, write, or execute code/shell commands unless you explicitly enable them.
|
@@ -232,7 +219,7 @@ janito -r -w -x "Run this code: print('Hello, world!')"
|
|
232
219
|
### Core CLI Options
|
233
220
|
| Option | Description |
|
234
221
|
|------------------------|-----------------------------------------------------------------------------|
|
235
|
-
|
222
|
+
|
236
223
|
| `--version` | Show program version |
|
237
224
|
| `--list-tools` | List all registered tools |
|
238
225
|
| `--list-providers` | List all supported LLM providers |
|
@@ -136,19 +136,6 @@ Janito has configuration options, like `--set api-key API_KEY` and `--set provid
|
|
136
136
|
|
137
137
|
### Advanced Options
|
138
138
|
|
139
|
-
- **Enable Inline Web File Viewer for Clickable Links**
|
140
|
-
|
141
|
-
By default, Janito can open referenced files in a browser-based viewer when you click on file links in supported terminals. To enable this feature for your session, use the `--web` flag:
|
142
|
-
|
143
|
-
```bash
|
144
|
-
janito --web
|
145
|
-
```
|
146
|
-
|
147
|
-
This starts the lightweight web file viewer () in the background, allowing you to inspect files referenced in responses directly in your browser. Combine with interactive mode or prompts as needed.
|
148
|
-
|
149
|
-
> **Tip:** Use with the interactive shell for the best experience with clickable file links.
|
150
|
-
|
151
|
-
|
152
139
|
- **Enable Execution Tools (Code/Shell Execution)**
|
153
140
|
|
154
141
|
By default, **all tool privileges (read, write, execute)** are disabled for safety. This means Janito starts with no permissions to run tools that read, write, or execute code/shell commands unless you explicitly enable them.
|
@@ -201,7 +188,7 @@ janito -r -w -x "Run this code: print('Hello, world!')"
|
|
201
188
|
### Core CLI Options
|
202
189
|
| Option | Description |
|
203
190
|
|------------------------|-----------------------------------------------------------------------------|
|
204
|
-
|
191
|
+
|
205
192
|
| `--version` | Show program version |
|
206
193
|
| `--list-tools` | List all registered tools |
|
207
194
|
| `--list-providers` | List all supported LLM providers |
|
@@ -0,0 +1,138 @@
|
|
1
|
+
Below is a **minimal-yet-complete “router loop”** that lets any Chat Completions model talk to a remote **MCP server** exactly the same way the Agents SDK/Responses API does under the hood.
|
2
|
+
Feel free to copy-paste and adapt.
|
3
|
+
|
4
|
+
---
|
5
|
+
|
6
|
+
## 0 Dependencies & setup
|
7
|
+
|
8
|
+
```bash
|
9
|
+
pip install openai httpx python-dotenv # ↩︎ async-friendly HTTP client
|
10
|
+
export OPENAI_API_KEY=sk-...
|
11
|
+
```
|
12
|
+
|
13
|
+
---
|
14
|
+
|
15
|
+
## 1 One-time discovery of all MCP tools
|
16
|
+
|
17
|
+
```python
|
18
|
+
import httpx, json, os
|
19
|
+
from openai import OpenAI
|
20
|
+
|
21
|
+
client = OpenAI() # Chat Completions client
|
22
|
+
MCP_SERVERS = { # label → URL
|
23
|
+
"weather": "http://localhost:8000/v1/mcp",
|
24
|
+
}
|
25
|
+
|
26
|
+
tool_registry = {} # name → {id, server, schema}
|
27
|
+
for label, url in MCP_SERVERS.items():
|
28
|
+
r = httpx.post(url, json={"method": "list_tools", "id": 1})
|
29
|
+
for t in r.json()["result"]:
|
30
|
+
tool_registry[t["name"]] = {
|
31
|
+
"id": t["id"],
|
32
|
+
"server": url,
|
33
|
+
"schema": t, # already JSON-Schema compliant ✅
|
34
|
+
}
|
35
|
+
|
36
|
+
TOOLS_FOR_OPENAI = [v["schema"] for v in tool_registry.values()]
|
37
|
+
```
|
38
|
+
|
39
|
+
The list-tools → JSON-Schema mapping is exactly what Chat Completions expects (via the `tools` parameter) ([help.openai.com][1]).
|
40
|
+
|
41
|
+
---
|
42
|
+
|
43
|
+
## 2 Chat → router loop
|
44
|
+
|
45
|
+
```python
|
46
|
+
messages = [
|
47
|
+
{"role": "system",
|
48
|
+
"content": "You can call the tools provided to help the user."},
|
49
|
+
{"role": "user",
|
50
|
+
"content": "What’s the weather in Zurich right now?"}
|
51
|
+
]
|
52
|
+
|
53
|
+
while True:
|
54
|
+
resp = client.chat.completions.create(
|
55
|
+
model = "gpt-4o-mini",
|
56
|
+
messages = messages,
|
57
|
+
tools = TOOLS_FOR_OPENAI,
|
58
|
+
tool_choice = "auto", # let the model decide :contentReference[oaicite:1]{index=1}
|
59
|
+
temperature = 0,
|
60
|
+
)
|
61
|
+
|
62
|
+
msg = resp.choices[0].message
|
63
|
+
|
64
|
+
# CASE A – assistant wants to call one or more tools
|
65
|
+
if msg.tool_calls:
|
66
|
+
messages.append(msg) # keep the call stub
|
67
|
+
for call in msg.tool_calls:
|
68
|
+
tool_name = call.function.name
|
69
|
+
args = json.loads(call.function.arguments)
|
70
|
+
|
71
|
+
m = tool_registry[tool_name]
|
72
|
+
result = httpx.post(
|
73
|
+
m["server"],
|
74
|
+
json={
|
75
|
+
"method": "call_tool",
|
76
|
+
"params": {"id": m["id"], "arguments": args},
|
77
|
+
"id": 42
|
78
|
+
}
|
79
|
+
).json()["result"]
|
80
|
+
|
81
|
+
# Echo the result back so the model can finish the thought
|
82
|
+
messages.append({
|
83
|
+
"role": "tool",
|
84
|
+
"tool_call_id": call.id,
|
85
|
+
"content": json.dumps(result)
|
86
|
+
})
|
87
|
+
continue # ↩︎ model may want more tool calls.
|
88
|
+
|
89
|
+
# CASE B – we’re done (plain assistant message)
|
90
|
+
print(msg.content)
|
91
|
+
break
|
92
|
+
```
|
93
|
+
|
94
|
+
**Key points**
|
95
|
+
|
96
|
+
| Why | What to remember |
|
97
|
+
| ------------------ | ---------------------------------------------------------------------------- |
|
98
|
+
| **Tool discovery** | Cache the JSON once; refresh on a schedule to save tokens. |
|
99
|
+
| **Routing** | Map *tool name* → (MCP URL, tool id). No need to expose ids to the model. |
|
100
|
+
| **Multiple calls** | The loop continues until the model returns a message *without* `tool_calls`. |
|
101
|
+
| **Safety** | Validate the tool name and arguments against `tool_registry` before firing. |
|
102
|
+
|
103
|
+
---
|
104
|
+
|
105
|
+
## 3 Streaming (optional)
|
106
|
+
|
107
|
+
Add `stream=True` to the `client.chat.completions.create` call and accumulate the chunks’ `delta` fields until you see `finish_reason == "tool_calls"` or `"stop"` ([cookbook.openai.com][2]).
|
108
|
+
Streamed tool calls arrive in exactly the same order; route each as soon as the JSON fragment closes to slash latency.
|
109
|
+
|
110
|
+
---
|
111
|
+
|
112
|
+
## 4 Handling more than one MCP server
|
113
|
+
|
114
|
+
Just keep extending `MCP_SERVERS` and the discovery loop; `tool_registry` remains a flat map, so collisions are impossible. The runtime cost is one HTTP request per server at startup.
|
115
|
+
|
116
|
+
---
|
117
|
+
|
118
|
+
## 5 Production checklist
|
119
|
+
|
120
|
+
| Risk | Mitigation |
|
121
|
+
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
|
122
|
+
| **Prompt-injection via tool output** | JSON-schema-validate **again** after the MCP call; escape any HTML. |
|
123
|
+
| **Runaway streams / DoS** | Timeouts on both Chat Completions and MCP HTTP calls; token/byte ceilings. |
|
124
|
+
| **Secrets in tool arguments** | Never log raw arguments; redact before shipping logs or traces. |
|
125
|
+
| **Token cost for huge schemas** | SHA-256 hash the last tool list; only resend when it changes. |
|
126
|
+
| **Model refuses to call a tool** | Use `tool_choice={"type":"function","function":{"name":"…"}}` or `"required"` to force a call ([learn.microsoft.com][3]). |
|
127
|
+
|
128
|
+
---
|
129
|
+
|
130
|
+
### Why not just switch to the Responses API?
|
131
|
+
|
132
|
+
Chat Completions works fine, but with Responses you get automatic **list\_tools/call\_tool** plumbing, background runs, retries, and built-in tracing for free. If you’re starting fresh, Responses is simpler; if you’re locked into Chat Completions (e.g., legacy infra, cost model), the loop above is all you need.
|
133
|
+
|
134
|
+
Happy hacking!
|
135
|
+
|
136
|
+
[1]: https://help.openai.com/en/articles/8555517-function-calling-in-the-openai-api "Function Calling in the OpenAI API | OpenAI Help Center"
|
137
|
+
[2]: https://cookbook.openai.com/examples/how_to_stream_completions "How to stream completions"
|
138
|
+
[3]: https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/function-calling "How to use function calling with Azure OpenAI in Azure AI Foundry Models - Azure OpenAI | Microsoft Learn"
|
@@ -20,7 +20,7 @@ def setup_agent(
|
|
20
20
|
output_queue=None,
|
21
21
|
verbose_tools=False,
|
22
22
|
verbose_agent=False,
|
23
|
-
|
23
|
+
|
24
24
|
allowed_permissions=None,
|
25
25
|
profile=None,
|
26
26
|
profile_system_prompt=None,
|
@@ -156,6 +156,7 @@ def setup_agent(
|
|
156
156
|
agent.template_vars["profile"] = profile
|
157
157
|
# Store template path and context for dynamic prompt refresh
|
158
158
|
agent.system_prompt_template = str(template_path)
|
159
|
+
|
159
160
|
agent._template_vars = context.copy()
|
160
161
|
agent._original_template_vars = context.copy()
|
161
162
|
return agent
|
@@ -170,7 +171,7 @@ def create_configured_agent(
|
|
170
171
|
verbose_agent=False,
|
171
172
|
templates_dir=None,
|
172
173
|
zero_mode=False,
|
173
|
-
|
174
|
+
|
174
175
|
allowed_permissions=None,
|
175
176
|
profile=None,
|
176
177
|
profile_system_prompt=None,
|
@@ -212,7 +213,7 @@ def create_configured_agent(
|
|
212
213
|
output_queue=output_queue,
|
213
214
|
verbose_tools=verbose_tools,
|
214
215
|
verbose_agent=verbose_agent,
|
215
|
-
|
216
|
+
|
216
217
|
allowed_permissions=allowed_permissions,
|
217
218
|
profile=profile,
|
218
219
|
profile_system_prompt=profile_system_prompt,
|
@@ -0,0 +1 @@
|
|
1
|
+
You are a helpful assistant.
|
@@ -0,0 +1,153 @@
|
|
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
|
+
from __future__ import annotations
|
27
|
+
|
28
|
+
from types import MethodType
|
29
|
+
from typing import List, Optional
|
30
|
+
|
31
|
+
from rich.console import Console
|
32
|
+
|
33
|
+
from janito.cli.chat_mode.session import ChatSession
|
34
|
+
from janito.provider_registry import ProviderRegistry
|
35
|
+
from janito.llm.driver_config import LLMDriverConfig
|
36
|
+
|
37
|
+
__all__ = ["ChatScriptRunner"]
|
38
|
+
|
39
|
+
|
40
|
+
auth_warning = (
|
41
|
+
"[yellow]ChatScriptRunner is executing in stubbed-agent mode; no calls to an "
|
42
|
+
"external LLM provider will be made.[/yellow]"
|
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
|
+
chat_session_kwargs["args"] = SimpleNamespace(
|
85
|
+
profile="developer",
|
86
|
+
provider=self.provider,
|
87
|
+
model=self.model,
|
88
|
+
)
|
89
|
+
|
90
|
+
# Create the ChatSession instance **after** we monkey-patch methods that rely on
|
91
|
+
# prompt-toolkit so that no attempt is made to instantiate terminal UIs in
|
92
|
+
# a headless environment like CI.
|
93
|
+
|
94
|
+
# 1) Patch *ChatSession._create_prompt_session* to do nothing – the
|
95
|
+
# interactive session object is irrelevant for scripted runs.
|
96
|
+
from types import MethodType as _MT
|
97
|
+
if "_original_create_prompt_session" not in ChatSession.__dict__:
|
98
|
+
ChatSession._original_create_prompt_session = ChatSession._create_prompt_session # type: ignore[attr-defined]
|
99
|
+
ChatSession._create_prompt_session = _MT(lambda _self: None, ChatSession) # type: ignore[method-assign]
|
100
|
+
|
101
|
+
# Resolve provider instance now so that ChatSession uses a ready agent
|
102
|
+
provider_instance = ProviderRegistry().get_instance(self.provider)
|
103
|
+
if provider_instance is None:
|
104
|
+
raise RuntimeError(f"Provider '{self.provider}' is not available on this system.")
|
105
|
+
driver_config = LLMDriverConfig(model=self.model)
|
106
|
+
chat_session_kwargs.setdefault("provider_instance", provider_instance)
|
107
|
+
chat_session_kwargs.setdefault("llm_driver_config", driver_config)
|
108
|
+
|
109
|
+
self.chat_session = ChatSession(console=self.console, **chat_session_kwargs)
|
110
|
+
|
111
|
+
|
112
|
+
# Monkey-patch the *ChatSession._handle_input* method so that it pops
|
113
|
+
# from our in-memory queue instead of reading from stdin.
|
114
|
+
def _script_handle_input(this: ChatSession, _prompt_session_unused): # noqa: D401
|
115
|
+
if not self._input_queue:
|
116
|
+
# Signal normal shutdown
|
117
|
+
this._handle_exit()
|
118
|
+
return None
|
119
|
+
return self._input_queue.pop(0)
|
120
|
+
|
121
|
+
# Bind the method to the *chat_session* instance.
|
122
|
+
self.chat_session._handle_input = MethodType( # type: ignore[assignment]
|
123
|
+
_script_handle_input, self.chat_session
|
124
|
+
)
|
125
|
+
|
126
|
+
# ---------------------------------------------------------------------
|
127
|
+
# Public helpers
|
128
|
+
# ---------------------------------------------------------------------
|
129
|
+
def run(self) -> str:
|
130
|
+
"""Execute the chat session and return the captured transcript."""
|
131
|
+
self.chat_session.run()
|
132
|
+
return self.console.export_text()
|
133
|
+
|
134
|
+
# ---------------------------------------------------------------------
|
135
|
+
# Helpers to introspect results
|
136
|
+
# ---------------------------------------------------------------------
|
137
|
+
def get_history(self):
|
138
|
+
"""Return the structured conversation history produced by the LLM."""
|
139
|
+
try:
|
140
|
+
return self.chat_session.shell_state.conversation_history.get_history()
|
141
|
+
except Exception:
|
142
|
+
return []
|
143
|
+
|
144
|
+
def get_last_response(self) -> str | None:
|
145
|
+
"""Return the *assistant* content of the last message, if any."""
|
146
|
+
history = self.get_history()
|
147
|
+
for message in reversed(history):
|
148
|
+
if message.get("role") == "assistant":
|
149
|
+
return message.get("content")
|
150
|
+
return None
|
151
|
+
|
152
|
+
# Convenience alias so tests can simply call *runner()*
|
153
|
+
__call__ = run
|
@@ -54,7 +54,7 @@ class ChatSession:
|
|
54
54
|
args=None,
|
55
55
|
verbose_tools=False,
|
56
56
|
verbose_agent=False,
|
57
|
-
|
57
|
+
|
58
58
|
allowed_permissions=None,
|
59
59
|
):
|
60
60
|
|
@@ -76,12 +76,9 @@ class ChatSession:
|
|
76
76
|
from janito.cli.chat_mode.session_profile_select import select_profile
|
77
77
|
|
78
78
|
result = select_profile()
|
79
|
-
if (
|
80
|
-
|
81
|
-
|
82
|
-
and result.get("profile_system_prompt")
|
83
|
-
):
|
84
|
-
profile_system_prompt = result["profile_system_prompt"]
|
79
|
+
if isinstance(result, dict):
|
80
|
+
profile = result.get("profile")
|
81
|
+
profile_system_prompt = result.get("profile_system_prompt")
|
85
82
|
elif isinstance(result, str) and result.startswith("role:"):
|
86
83
|
role = result[len("role:") :].strip()
|
87
84
|
profile = "developer"
|
@@ -105,7 +102,7 @@ class ChatSession:
|
|
105
102
|
role=role,
|
106
103
|
verbose_tools=verbose_tools,
|
107
104
|
verbose_agent=verbose_agent,
|
108
|
-
|
105
|
+
|
109
106
|
allowed_permissions=allowed_permissions,
|
110
107
|
profile=profile,
|
111
108
|
profile_system_prompt=profile_system_prompt,
|
@@ -163,6 +160,14 @@ class ChatSession:
|
|
163
160
|
f"[bold green]Janito Chat Mode v{__version__}[/bold green]"
|
164
161
|
)
|
165
162
|
self.console.print("[green]/help for commands /exit or Ctrl+C to quit[/green]")
|
163
|
+
import os
|
164
|
+
cwd = os.getcwd()
|
165
|
+
home = os.path.expanduser('~')
|
166
|
+
if cwd.startswith(home):
|
167
|
+
cwd_display = '~' + cwd[len(home):]
|
168
|
+
else:
|
169
|
+
cwd_display = cwd
|
170
|
+
self.console.print(f"[green]Working Dir:[/green] {cwd_display}")
|
166
171
|
|
167
172
|
# Inform user if no privileges are enabled
|
168
173
|
from janito.cli.chat_mode.shell.commands._priv_check import user_has_any_privileges
|
@@ -185,40 +190,55 @@ class ChatSession:
|
|
185
190
|
continue
|
186
191
|
if self._handle_exit_conditions(cmd_input):
|
187
192
|
break
|
188
|
-
if
|
189
|
-
handle_command(cmd_input, shell_state=self.shell_state)
|
193
|
+
if self._handle_command_input(cmd_input):
|
190
194
|
continue
|
191
195
|
self.user_input_history.append(cmd_input)
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
+
self._process_prompt(cmd_input)
|
197
|
+
|
198
|
+
def _handle_command_input(self, cmd_input):
|
199
|
+
if cmd_input.startswith("/"):
|
200
|
+
handle_command(cmd_input, shell_state=self.shell_state)
|
201
|
+
return True
|
202
|
+
if cmd_input.startswith("!"):
|
203
|
+
# Pass everything after ! to the bang handler
|
204
|
+
handle_command(f"! {cmd_input[1:]}", shell_state=self.shell_state)
|
205
|
+
return True
|
206
|
+
return False
|
207
|
+
|
208
|
+
def _process_prompt(self, cmd_input):
|
209
|
+
try:
|
210
|
+
import time
|
211
|
+
final_event = (
|
212
|
+
self._prompt_handler.agent.last_event
|
213
|
+
if hasattr(self._prompt_handler.agent, "last_event")
|
214
|
+
else None
|
215
|
+
)
|
216
|
+
start_time = time.time()
|
217
|
+
self._prompt_handler.run_prompt(cmd_input)
|
218
|
+
end_time = time.time()
|
219
|
+
elapsed = end_time - start_time
|
220
|
+
self.msg_count += 1
|
221
|
+
# After prompt, print the stat line using the shared core function
|
222
|
+
from janito.formatting_token import print_token_message_summary
|
223
|
+
|
224
|
+
usage = self.performance_collector.get_last_request_usage()
|
225
|
+
print_token_message_summary(self.console, self.msg_count, usage, elapsed=elapsed)
|
226
|
+
# Print exit reason if present in the final event
|
227
|
+
if final_event and hasattr(final_event, "metadata"):
|
228
|
+
exit_reason = (
|
229
|
+
final_event.metadata.get("exit_reason")
|
230
|
+
if hasattr(final_event, "metadata")
|
196
231
|
else None
|
197
232
|
)
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
from janito.formatting_token import print_token_message_summary
|
202
|
-
|
203
|
-
usage = self.performance_collector.get_last_request_usage()
|
204
|
-
print_token_message_summary(self.console, self.msg_count, usage)
|
205
|
-
# Print exit reason if present in the final event
|
206
|
-
if final_event and hasattr(final_event, "metadata"):
|
207
|
-
exit_reason = (
|
208
|
-
final_event.metadata.get("exit_reason")
|
209
|
-
if hasattr(final_event, "metadata")
|
210
|
-
else None
|
233
|
+
if exit_reason:
|
234
|
+
self.console.print(
|
235
|
+
f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
|
211
236
|
)
|
212
|
-
if exit_reason:
|
213
|
-
self.console.print(
|
214
|
-
f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
|
215
|
-
)
|
216
|
-
|
217
|
-
except Exception as exc:
|
218
|
-
self.console.print(f"[red]Exception in agent: {exc}[/red]")
|
219
|
-
import traceback
|
220
237
|
|
221
|
-
|
238
|
+
except Exception as exc:
|
239
|
+
self.console.print(f"[red]Exception in agent: {exc}[/red]")
|
240
|
+
import traceback
|
241
|
+
self.console.print(traceback.format_exc())
|
222
242
|
|
223
243
|
def _create_prompt_session(self):
|
224
244
|
return PromptSession(
|
@@ -22,7 +22,7 @@ def select_profile():
|
|
22
22
|
style=custom_style
|
23
23
|
).ask()
|
24
24
|
if answer == "helpful assistant":
|
25
|
-
return {"profile":
|
25
|
+
return {"profile": "assistant", "profile_system_prompt": None}
|
26
26
|
if answer == "using role...":
|
27
27
|
role_name = questionary.text("Enter the role name:").ask()
|
28
28
|
return f"role:{role_name}"
|