janito 2.16.0__tar.gz → 2.17.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.16.0 → janito-2.17.1}/CHANGELOG.md +28 -0
- {janito-2.16.0 → janito-2.17.1}/PKG-INFO +1 -1
- janito-2.17.1/docs/cerebras-setup.md +56 -0
- {janito-2.16.0 → janito-2.17.1}/docs/supported-providers-models.md +19 -1
- {janito-2.16.0 → janito-2.17.1}/janito/agent/setup_agent.py +1 -1
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/list_drivers.py +1 -0
- janito-2.17.1/janito/cli/cli_commands/set_api_key.py +30 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/prompt_setup.py +3 -0
- janito-2.17.1/janito/drivers/cerebras/__init__.py +1 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/__init__.py +1 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/alibaba/provider.py +1 -3
- janito-2.17.1/janito/providers/cerebras/__init__.py +1 -0
- janito-2.17.1/janito/providers/cerebras/model_info.py +76 -0
- janito-2.17.1/janito/providers/cerebras/provider.py +145 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/read_files.py +1 -1
- {janito-2.16.0 → janito-2.17.1}/janito/tools/path_security.py +14 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/tools_adapter.py +118 -26
- {janito-2.16.0 → janito-2.17.1}/janito.egg-info/PKG-INFO +1 -1
- {janito-2.16.0 → janito-2.17.1}/janito.egg-info/SOURCES.txt +6 -1
- {janito-2.16.0 → janito-2.17.1}/mkdocs.yml +1 -1
- {janito-2.16.0 → janito-2.17.1}/tests/adapters/local/test_read_files.py +1 -1
- janito-2.17.1/tests/test_provider_cerebras.py +93 -0
- janito-2.16.0/docs/index.md +0 -26
- janito-2.16.0/janito/cli/cli_commands/set_api_key.py +0 -19
- {janito-2.16.0 → janito-2.17.1}/.codespellrc +0 -0
- {janito-2.16.0 → janito-2.17.1}/.gitattributes +0 -0
- {janito-2.16.0 → janito-2.17.1}/.github/workflows/python-app.yml.disabled +0 -0
- {janito-2.16.0 → janito-2.17.1}/.gitignore +0 -0
- {janito-2.16.0 → janito-2.17.1}/.pre-commit-config.yaml +0 -0
- {janito-2.16.0 → janito-2.17.1}/.secrets.baseline +0 -0
- {janito-2.16.0 → janito-2.17.1}/.vscode/settings.json +0 -0
- {janito-2.16.0 → janito-2.17.1}/CHANGELOG_2.16.0.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/LICENSE +0 -0
- {janito-2.16.0 → janito-2.17.1}/README-dev.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/README.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/UPDATING_DOCS.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/adding_mcp.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/DIV.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/Interfaces.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/TOOLBAR-STYLING.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/about/costs.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/about/vs-webchats.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/about/why.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/alternatives.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/code_intelligence/agentic-frameworks-comparison.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/code_intelligence/code-generation-challenges.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/code_intelligence/code-generation-observability.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/code_intelligence/our-approach.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/code_intelligence/why-string-replacement.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/concepts/analysis-style.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/concepts/human-guided-ai.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/concepts/index.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/concepts/language-model-clients.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/concepts/prompt-design-style.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/deepseek-setup.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/driver-flow.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/driver-request-cancellation.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/drivers/events.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/drivers.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/event-bus.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/configuration.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/developing.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/disabled-tools.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/installation.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/profiles.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/prompting/README.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/single-shot-terminal.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/terminal-shell.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/tools-developer-guide.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/using.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/guides/using_tools.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/code-generation-observability.png +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/code_generation_observability.png +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/happy-programmer.png +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/happy-programmer.svg +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/terminal-one-shot.png +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/terminal-shell.png +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/terminal_one_shot.png +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/imgs/terminal_shell.png +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/llm-drivers-required-config.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/llm-drivers.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/meta/developer-toolchain.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/meta/quality-checks.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/moonshotai-setup.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/reference/api.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/reference/azure-openai.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/reference/cli-options.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/reference/message-handler-model.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/reference/rich-message-handler.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/security.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/tools/search-text.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/tools-index.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/tools-natural-results.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/tools-precision.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/docs/z-ai-setup.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/git_diff.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/github_diff +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/README.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/__main__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/_version.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/agent/templates/profiles/system_prompt_template_Developer_with_Python_Tools.txt.j2 +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/agent/templates/profiles/system_prompt_template_model_conversation_without_tools_or_context.txt.j2 +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/bindings.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/chat_entry.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/prompt_style.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/script_runner.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/session.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/session_profile_select.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/autocomplete.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/_priv_check.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/_priv_status.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/bang.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/base.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/clear.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/conversation_restart.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/execute.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/help.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/history_view.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/lang.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/model.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/multi.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/privileges.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/prompt.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/read.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/role.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/session.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/session_control.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/tools.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/utility.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/verbose.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands/write.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/commands.bak.zip +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/input_history.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/session/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/session/history.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/session/manager.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/shell/session.bak.zip +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/chat_mode/toolbar.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/list_config.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/list_models.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/list_profiles.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/list_providers.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/list_providers_region.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/list_tools.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/model_selection.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/model_utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/show_config.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/cli_commands/show_system_prompt.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/config.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/console.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/core/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/core/event_logger.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/core/getters.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/core/model_guesser.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/core/runner.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/core/setters.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/core/unsetters.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/main.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/main_cli.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/prompt_core.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/prompt_handler.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/rich_terminal_reporter.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/single_shot_mode/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/single_shot_mode/handler.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/cli/verbose_output.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/config.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/config_manager.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/conversation_history.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/dir_walk_utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/docs/GETTING_STARTED.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/driver_events.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/drivers/azure_openai/driver.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/drivers/dashscope.bak.zip +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/drivers/openai/README.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/drivers/openai/driver.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/drivers/openai_responses.bak.zip +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/drivers/zai/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/drivers/zai/driver.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/event_bus/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/event_bus/bus.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/event_bus/event.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/event_bus/handler.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/event_bus/queue_bus.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/exceptions.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/formatting.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/formatting_token.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/gitignore_utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/i18n/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/i18n/messages.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/i18n/pt.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/README.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/agent.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/auth.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/auth_utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/driver.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/driver_config.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/driver_config_builder.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/driver_input.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/message_parts.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/model.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/llm/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/mkdocs.yml +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/perf_singleton.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/performance_collector.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/platform_discovery.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/provider_config.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/provider_registry.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/alibaba/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/alibaba/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/anthropic/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/anthropic/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/azure_openai/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/azure_openai/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/dashscope.bak.zip +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/deepseek/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/deepseek/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/deepseek/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/google/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/google/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/google/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/moonshotai/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/moonshotai/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/moonshotai/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/openai/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/openai/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/openai/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/openai/schema_generator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/registry.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/zai/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/zai/model_info.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/zai/provider.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/providers/zai/schema_generator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/regions/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/regions/cli.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/regions/geo_utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/regions/provider_regions.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/report_events.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/shell.bak.zip +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/DOCSTRING_STANDARD.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/README.md +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/adapter.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/ask_user.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/copy_file.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/create_directory.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/create_file.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/delete_text_in_file.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/fetch_url.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/find_files.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/get_file_outline/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/get_file_outline/core.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/get_file_outline/java_outline.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/get_file_outline/markdown_outline.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/get_file_outline/python_outline.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/get_file_outline/search_outline.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/move_file.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/open_html_in_browser.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/open_url.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/python_code_run.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/python_command_run.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/python_file_run.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/remove_directory.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/remove_file.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/replace_text_in_file.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/run_bash_command.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/run_powershell_command.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/search_text/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/search_text/core.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/search_text/match_lines.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/search_text/pattern_utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/search_text/traverse_directory.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/__init__.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/core.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/css_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/html_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/js_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/json_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/python_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/xml_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/adapters/local/view_file.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/disabled_tools.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/inspect_registry.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/outline_file.bak.zip +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/permissions.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/permissions_parse.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/tool_base.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/tool_events.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/tool_run_exception.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/tool_use_tracker.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/tool_utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/tools/tools_schema.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito/utils.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito.egg-info/dependency_links.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito.egg-info/entry_points.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito.egg-info/requires.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/janito.egg-info/top_level.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/pyproject.toml +0 -0
- {janito-2.16.0 → janito-2.17.1}/pytest.ini +0 -0
- {janito-2.16.0 → janito-2.17.1}/requirements-dev.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/requirements.txt +0 -0
- {janito-2.16.0 → janito-2.17.1}/setup.cfg +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/adapters/local/get_file_outline/test_core_outline.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_cli_list_models.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_cli_list_providers.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_cli_list_providers_alibaba.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_cli_list_providers_moonshotai.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_cli_version.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_disabled_tools.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_provider_alibaba.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tests/test_provider_moonshotai.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tools/release.py +0 -0
- {janito-2.16.0 → janito-2.17.1}/tox.ini +0 -0
@@ -4,6 +4,34 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
6
|
|
7
|
+
## [2.17.0] - 2025-08-05
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- **New Provider Support**
|
12
|
+
- **Cerebras Provider**: Added complete support for Cerebras with qwen-3-coder-480b model
|
13
|
+
- qwen-3-coder-480b: 32k context, reasoning-focused model with function calling support
|
14
|
+
|
15
|
+
- **Enhanced UX**
|
16
|
+
- Improved error handling for invalid provider names in set-api-key command
|
17
|
+
- Better error messages when provider is not found
|
18
|
+
|
19
|
+
### Changed
|
20
|
+
|
21
|
+
- **Provider Improvements**
|
22
|
+
- Updated Alibaba endpoint to international URL for better global access
|
23
|
+
- Simplified region display to 2-letter codes for cleaner output
|
24
|
+
- Improved driver listing and region display functionality
|
25
|
+
|
26
|
+
- **Zero Mode Enhancement**
|
27
|
+
- Zero mode now properly disables system prompt and tools for minimal interaction
|
28
|
+
|
29
|
+
### Fixed
|
30
|
+
|
31
|
+
- **Bug Fixes**
|
32
|
+
- Added missing tools adapter to Cerebras provider
|
33
|
+
- Improved error handling for invalid provider names in set-api-key command
|
34
|
+
|
7
35
|
## [2.16.0] - 2025-01-08
|
8
36
|
|
9
37
|
### Added
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Cerebras Setup Guide
|
2
|
+
|
3
|
+
This guide will help you set up Janito to use Cerebras as an LLM provider.
|
4
|
+
|
5
|
+
## Prerequisites
|
6
|
+
|
7
|
+
1. A Cerebras account
|
8
|
+
2. An API key from Cerebras
|
9
|
+
|
10
|
+
## Getting an API Key
|
11
|
+
|
12
|
+
1. Visit the [Cerebras API Keys page](https://api.cerebras.ai/)
|
13
|
+
2. Log in to your account
|
14
|
+
3. Generate a new API key
|
15
|
+
4. Copy the API key for use in Janito
|
16
|
+
|
17
|
+
## Configuration
|
18
|
+
|
19
|
+
To configure Janito to use Cerebras, you need to set your API key:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
janito --set-api-key YOUR_CEREBRAS_API_KEY -p cerebras
|
23
|
+
```
|
24
|
+
|
25
|
+
Replace `YOUR_CEREBRAS_API_KEY` with the API key you obtained from Cerebras.
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
After setting up your API key, you can use Cerebras models with Janito:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
janito -p cerebras "Hello, how are you?"
|
33
|
+
```
|
34
|
+
|
35
|
+
By default, Janito will use the `qwen-3-coder-480b` model. You can specify a different model if needed:
|
36
|
+
|
37
|
+
```bash
|
38
|
+
janito -p cerebras -m qwen-3-coder-480b "Explain quantum computing"
|
39
|
+
```
|
40
|
+
|
41
|
+
## Available Models
|
42
|
+
|
43
|
+
Cerebras offers several models through their API:
|
44
|
+
|
45
|
+
- `qwen-3-coder-480b`: 32k context, reasoning-focused model with function calling support
|
46
|
+
|
47
|
+
## Troubleshooting
|
48
|
+
|
49
|
+
If you encounter issues:
|
50
|
+
|
51
|
+
1. Verify your API key is correct and active
|
52
|
+
2. Check that you have internet connectivity
|
53
|
+
3. Ensure you're using a supported model name
|
54
|
+
4. Check the Cerebras status page for any service outages
|
55
|
+
|
56
|
+
For further assistance, consult the [Cerebras documentation](https://api.cerebras.ai/docs) or [Janito documentation](https://docs.janito.dev).
|
@@ -36,7 +36,7 @@ This page lists the supported providers and their available models.
|
|
36
36
|
- qwen-turbo
|
37
37
|
- qwen-plus
|
38
38
|
- qwen-max
|
39
|
-
- qwen3-coder-plus
|
39
|
+
- qwen3-coder-plus (default)
|
40
40
|
- qwen3-coder-480b-a35b-instruct
|
41
41
|
|
42
42
|
## Z.AI
|
@@ -44,4 +44,22 @@ This page lists the supported providers and their available models.
|
|
44
44
|
- glm-4.5
|
45
45
|
- glm-4.5-air
|
46
46
|
|
47
|
+
## Cerebras
|
48
|
+
|
49
|
+
**Production Models:**
|
50
|
+
- llama-4-scout-17b-16e-instruct
|
51
|
+
- llama-3.3-70b
|
52
|
+
- llama3.1-8b
|
53
|
+
- qwen-3-32b
|
54
|
+
|
55
|
+
**Preview Models:**
|
56
|
+
- llama-4-maverick-17b-128e-instruct
|
57
|
+
- qwen-3-235b-a22b-instruct-2507
|
58
|
+
- qwen-3-235b-a22b-thinking-2507
|
59
|
+
- qwen-3-coder-480b
|
60
|
+
- gpt-oss-120b
|
61
|
+
|
62
|
+
**Notes:**
|
63
|
+
- qwen-3-coder-480b: 32k context, reasoning-focused model with function calling support
|
64
|
+
|
47
65
|
<!-- Removed links to model_info.py files for all providers to avoid broken references. -->
|
@@ -167,7 +167,7 @@ def setup_agent(
|
|
167
167
|
"""
|
168
168
|
Creates an agent. A system prompt is rendered from a template only when a profile is specified.
|
169
169
|
"""
|
170
|
-
if no_tools_mode:
|
170
|
+
if no_tools_mode or zero_mode:
|
171
171
|
tools_provider = None
|
172
172
|
else:
|
173
173
|
tools_provider = get_local_tools_adapter()
|
@@ -92,6 +92,7 @@ def get_driver_info():
|
|
92
92
|
("janito.drivers.openai.driver", "OpenAIModelDriver"),
|
93
93
|
("janito.drivers.azure_openai.driver", "AzureOpenAIModelDriver"),
|
94
94
|
("janito.drivers.zai.driver", "ZAIModelDriver"),
|
95
|
+
("janito.drivers.cerebras.driver", "CerebrasModelDriver"),
|
95
96
|
]
|
96
97
|
|
97
98
|
for module_path, class_name in driver_modules:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"""
|
2
|
+
CLI Command: Set API key for the current or selected provider
|
3
|
+
"""
|
4
|
+
|
5
|
+
from janito.provider_config import set_api_key
|
6
|
+
from janito.llm.auth import LLMAuthManager
|
7
|
+
from janito.providers.registry import LLMProviderRegistry
|
8
|
+
|
9
|
+
|
10
|
+
def handle_set_api_key(args):
|
11
|
+
api_key = getattr(args, "set_api_key", None)
|
12
|
+
provider = getattr(args, "provider", None)
|
13
|
+
if not provider:
|
14
|
+
print("Error: --set-api-key requires -p/--provider to be specified.")
|
15
|
+
return
|
16
|
+
|
17
|
+
# Validate provider name
|
18
|
+
if provider not in LLMProviderRegistry.list_providers():
|
19
|
+
valid_providers = LLMProviderRegistry.list_providers()
|
20
|
+
print(f"Error: Unknown provider '{provider}'. Valid providers are: {', '.join(valid_providers)}")
|
21
|
+
return
|
22
|
+
|
23
|
+
try:
|
24
|
+
set_api_key(provider, api_key)
|
25
|
+
auth_manager = LLMAuthManager()
|
26
|
+
print(
|
27
|
+
f"API key set for provider '{provider}'. Auth file updated: {auth_manager._auth_file}"
|
28
|
+
)
|
29
|
+
except ValueError as e:
|
30
|
+
print(f"Error: {e}")
|
@@ -37,6 +37,8 @@ def setup_agent_and_prompt_handler(
|
|
37
37
|
no_tools_mode = False
|
38
38
|
if hasattr(args, 'no_tools_mode'):
|
39
39
|
no_tools_mode = getattr(args, 'no_tools_mode', False)
|
40
|
+
|
41
|
+
zero_mode = getattr(args, 'zero', False)
|
40
42
|
agent = create_configured_agent(
|
41
43
|
provider_instance=provider_instance,
|
42
44
|
llm_driver_config=llm_driver_config,
|
@@ -46,6 +48,7 @@ def setup_agent_and_prompt_handler(
|
|
46
48
|
allowed_permissions=allowed_permissions,
|
47
49
|
profile=profile,
|
48
50
|
profile_system_prompt=profile_system_prompt,
|
51
|
+
zero_mode=zero_mode,
|
49
52
|
no_tools_mode=no_tools_mode,
|
50
53
|
)
|
51
54
|
|
@@ -0,0 +1 @@
|
|
1
|
+
# Cerebras driver package
|
@@ -17,9 +17,7 @@ class AlibabaProvider(LLMProvider):
|
|
17
17
|
NAME = "alibaba"
|
18
18
|
MAINTAINER = "João Pinto <janito@ikignosis.org>"
|
19
19
|
MODEL_SPECS = MODEL_SPECS
|
20
|
-
DEFAULT_MODEL =
|
21
|
-
"qwen3-coder-plus" # Options: qwen-turbo, qwen-plus, qwen-max, qwen3-coder-plus
|
22
|
-
)
|
20
|
+
DEFAULT_MODEL = "qwen3-coder-plus" # 128k context, coding-focused model
|
23
21
|
|
24
22
|
def __init__(
|
25
23
|
self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
|
@@ -0,0 +1 @@
|
|
1
|
+
# Cerebras provider package
|
@@ -0,0 +1,76 @@
|
|
1
|
+
"""Model specifications for Cerebras Inference API."""
|
2
|
+
|
3
|
+
from janito.llm.model import LLMModelInfo
|
4
|
+
|
5
|
+
MODEL_SPECS = {
|
6
|
+
"qwen-3-32b": LLMModelInfo(
|
7
|
+
name="qwen-3-32b",
|
8
|
+
max_input=128000,
|
9
|
+
max_response=16384,
|
10
|
+
default_temp=0.7,
|
11
|
+
driver="CerebrasModelDriver",
|
12
|
+
other={
|
13
|
+
"description": "Qwen 3 32B model for general instruction following",
|
14
|
+
"pricing": {
|
15
|
+
"input_per_1k_tokens": 0.0002,
|
16
|
+
"output_per_1k_tokens": 0.0006
|
17
|
+
}
|
18
|
+
}
|
19
|
+
),
|
20
|
+
"qwen-3-235b-a22b-instruct-2507": LLMModelInfo(
|
21
|
+
name="qwen-3-235b-a22b-instruct-2507",
|
22
|
+
max_input=128000,
|
23
|
+
max_response=16384,
|
24
|
+
default_temp=0.7,
|
25
|
+
driver="CerebrasModelDriver",
|
26
|
+
other={
|
27
|
+
"description": "Qwen 3 235B A22B instruction-tuned model (preview)",
|
28
|
+
"pricing": {
|
29
|
+
"input_per_1k_tokens": 0.001,
|
30
|
+
"output_per_1k_tokens": 0.003
|
31
|
+
}
|
32
|
+
}
|
33
|
+
),
|
34
|
+
"qwen-3-235b-a22b-thinking-2507": LLMModelInfo(
|
35
|
+
name="qwen-3-235b-a22b-thinking-2507",
|
36
|
+
max_input=128000,
|
37
|
+
max_response=16384,
|
38
|
+
default_temp=0.7,
|
39
|
+
driver="CerebrasModelDriver",
|
40
|
+
other={
|
41
|
+
"description": "Qwen 3 235B A22B thinking model for reasoning tasks (preview)",
|
42
|
+
"pricing": {
|
43
|
+
"input_per_1k_tokens": 0.001,
|
44
|
+
"output_per_1k_tokens": 0.003
|
45
|
+
}
|
46
|
+
}
|
47
|
+
),
|
48
|
+
"qwen-3-coder-480b": LLMModelInfo(
|
49
|
+
name="qwen-3-coder-480b",
|
50
|
+
max_input=128000,
|
51
|
+
max_response=16384,
|
52
|
+
default_temp=0.7,
|
53
|
+
driver="CerebrasModelDriver",
|
54
|
+
other={
|
55
|
+
"description": "Qwen 3 Coder 480B model for programming tasks (preview)",
|
56
|
+
"pricing": {
|
57
|
+
"input_per_1k_tokens": 0.002,
|
58
|
+
"output_per_1k_tokens": 0.006
|
59
|
+
}
|
60
|
+
}
|
61
|
+
),
|
62
|
+
"gpt-oss-120b": LLMModelInfo(
|
63
|
+
name="gpt-oss-120b",
|
64
|
+
max_input=128000,
|
65
|
+
max_response=16384,
|
66
|
+
default_temp=0.7,
|
67
|
+
driver="CerebrasModelDriver",
|
68
|
+
other={
|
69
|
+
"description": "GPT-OSS 120B open-source model (preview)",
|
70
|
+
"pricing": {
|
71
|
+
"input_per_1k_tokens": 0.0008,
|
72
|
+
"output_per_1k_tokens": 0.0024
|
73
|
+
}
|
74
|
+
}
|
75
|
+
)
|
76
|
+
}
|
@@ -0,0 +1,145 @@
|
|
1
|
+
"""Cerebras Inference provider implementation."""
|
2
|
+
|
3
|
+
from typing import Dict, Any
|
4
|
+
from janito.llm.provider import LLMProvider
|
5
|
+
from janito.llm.auth import LLMAuthManager
|
6
|
+
from janito.llm.driver_config import LLMDriverConfig
|
7
|
+
from janito.drivers.openai.driver import OpenAIModelDriver
|
8
|
+
from janito.tools import get_local_tools_adapter
|
9
|
+
from janito.providers.registry import LLMProviderRegistry
|
10
|
+
from .model_info import MODEL_SPECS
|
11
|
+
|
12
|
+
|
13
|
+
class CerebrasProvider(LLMProvider):
|
14
|
+
"""Cerebras Inference API provider."""
|
15
|
+
|
16
|
+
name = "cerebras"
|
17
|
+
NAME = "cerebras"
|
18
|
+
DEFAULT_MODEL = "qwen-3-coder-480b"
|
19
|
+
MAINTAINER = "João Pinto <janito@ikignosis.org>"
|
20
|
+
MODEL_SPECS = MODEL_SPECS
|
21
|
+
|
22
|
+
def __init__(self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None):
|
23
|
+
"""Initialize Cerebras provider with optional configuration."""
|
24
|
+
super().__init__()
|
25
|
+
self._tools_adapter = get_local_tools_adapter()
|
26
|
+
self._driver = None
|
27
|
+
self._tools_adapter = get_local_tools_adapter()
|
28
|
+
self._driver = None
|
29
|
+
if not self.available:
|
30
|
+
return
|
31
|
+
|
32
|
+
self._initialize_config(auth_manager, config)
|
33
|
+
self._setup_model_config()
|
34
|
+
self.fill_missing_device_info(self._driver_config)
|
35
|
+
|
36
|
+
if not self.available:
|
37
|
+
return
|
38
|
+
|
39
|
+
self._initialize_config(None, None)
|
40
|
+
self._driver_config.base_url = "https://api.cerebras.ai/v1"
|
41
|
+
|
42
|
+
def _initialize_config(self, auth_manager, config):
|
43
|
+
"""Initialize configuration and API key."""
|
44
|
+
self.auth_manager = auth_manager or LLMAuthManager()
|
45
|
+
self._api_key = self.auth_manager.get_credentials(type(self).NAME)
|
46
|
+
if not self._api_key:
|
47
|
+
from janito.llm.auth_utils import handle_missing_api_key
|
48
|
+
|
49
|
+
handle_missing_api_key(self.name, "CEREBRAS_API_KEY")
|
50
|
+
|
51
|
+
self._driver_config = config or LLMDriverConfig(model=None)
|
52
|
+
if not self._driver_config.model:
|
53
|
+
self._driver_config.model = self.DEFAULT_MODEL
|
54
|
+
if not self._driver_config.api_key:
|
55
|
+
self._driver_config.api_key = self._api_key
|
56
|
+
|
57
|
+
self._setup_model_config()
|
58
|
+
self.fill_missing_device_info(self._driver_config)
|
59
|
+
|
60
|
+
def _setup_model_config(self):
|
61
|
+
"""Configure token limits based on model specifications."""
|
62
|
+
model_name = self._driver_config.model
|
63
|
+
model_spec = self.MODEL_SPECS.get(model_name)
|
64
|
+
|
65
|
+
# Reset token parameters
|
66
|
+
if hasattr(self._driver_config, "max_tokens"):
|
67
|
+
self._driver_config.max_tokens = None
|
68
|
+
if hasattr(self._driver_config, "max_completion_tokens"):
|
69
|
+
self._driver_config.max_completion_tokens = None
|
70
|
+
|
71
|
+
if model_spec:
|
72
|
+
# Set context length
|
73
|
+
if hasattr(model_spec, "context") and model_spec.context:
|
74
|
+
self._driver_config.context_length = model_spec.context
|
75
|
+
|
76
|
+
# Set max tokens based on model spec
|
77
|
+
if hasattr(model_spec, "max_response") and model_spec.max_response:
|
78
|
+
self._driver_config.max_tokens = model_spec.max_response
|
79
|
+
|
80
|
+
# Set max completion tokens if thinking is supported
|
81
|
+
if getattr(model_spec, "thinking_supported", False):
|
82
|
+
max_cot = getattr(model_spec, "max_cot", None)
|
83
|
+
if max_cot and max_cot != "N/A":
|
84
|
+
self._driver_config.max_completion_tokens = int(max_cot)
|
85
|
+
else:
|
86
|
+
max_response = getattr(model_spec, "max_response", None)
|
87
|
+
if max_response and max_response != "N/A":
|
88
|
+
self._driver_config.max_tokens = int(max_response)
|
89
|
+
|
90
|
+
@property
|
91
|
+
@property
|
92
|
+
def driver(self) -> OpenAIModelDriver:
|
93
|
+
if not self.available:
|
94
|
+
raise ImportError(
|
95
|
+
f"CerebrasProvider unavailable: {self.unavailable_reason}"
|
96
|
+
)
|
97
|
+
if self._driver is None:
|
98
|
+
self._driver = self.create_driver()
|
99
|
+
return self._driver
|
100
|
+
|
101
|
+
@property
|
102
|
+
def available(self):
|
103
|
+
return OpenAIModelDriver.available
|
104
|
+
|
105
|
+
@property
|
106
|
+
def unavailable_reason(self):
|
107
|
+
return OpenAIModelDriver.unavailable_reason
|
108
|
+
|
109
|
+
def create_driver(self) -> OpenAIModelDriver:
|
110
|
+
"""Create and return an OpenAI-compatible Cerebras driver instance."""
|
111
|
+
driver = OpenAIModelDriver(
|
112
|
+
tools_adapter=self._tools_adapter, provider_name=self.name
|
113
|
+
)
|
114
|
+
driver.config = self._driver_config
|
115
|
+
return driver
|
116
|
+
|
117
|
+
@property
|
118
|
+
def driver_config(self):
|
119
|
+
"""Return the driver configuration."""
|
120
|
+
return self._driver_config
|
121
|
+
|
122
|
+
def is_model_available(self, model_name: str) -> bool:
|
123
|
+
"""Check if a model is available for this provider."""
|
124
|
+
return model_name in self.MODEL_SPECS
|
125
|
+
|
126
|
+
def get_model_info(self, model_name: str = None) -> Dict[str, Any]:
|
127
|
+
"""Get model information for the specified model or all models."""
|
128
|
+
if model_name is None:
|
129
|
+
return {
|
130
|
+
name: model_info.to_dict()
|
131
|
+
for name, model_info in self.MODEL_SPECS.items()
|
132
|
+
}
|
133
|
+
|
134
|
+
if model_name in self.MODEL_SPECS:
|
135
|
+
return self.MODEL_SPECS[model_name].to_dict()
|
136
|
+
|
137
|
+
return None
|
138
|
+
|
139
|
+
def execute_tool(self, tool_name: str, event_bus, *args, **kwargs):
|
140
|
+
self._tools_adapter.event_bus = event_bus
|
141
|
+
return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
|
142
|
+
|
143
|
+
|
144
|
+
# Register the provider
|
145
|
+
LLMProviderRegistry.register(CerebrasProvider.name, CerebrasProvider)
|
@@ -135,6 +135,7 @@ def _extract_path_keys_from_schema(schema: Mapping[str, Any]) -> set[str]:
|
|
135
135
|
path_keys: set[str] = set()
|
136
136
|
if schema is not None:
|
137
137
|
for k, v in schema.get("properties", {}).items():
|
138
|
+
# Handle direct path strings
|
138
139
|
if v.get("format") == "path" or (
|
139
140
|
v.get("type") == "string"
|
140
141
|
and (
|
@@ -144,6 +145,19 @@ def _extract_path_keys_from_schema(schema: Mapping[str, Any]) -> set[str]:
|
|
144
145
|
)
|
145
146
|
):
|
146
147
|
path_keys.add(k)
|
148
|
+
# Handle arrays of path strings
|
149
|
+
elif v.get("type") == "array" and "items" in v:
|
150
|
+
items = v["items"]
|
151
|
+
if items.get("format") == "path" or (
|
152
|
+
items.get("type") == "string"
|
153
|
+
and (
|
154
|
+
"path" in items.get("description", "").lower()
|
155
|
+
or "path" in v.get("description", "").lower()
|
156
|
+
or k.endswith("paths")
|
157
|
+
or k == "paths"
|
158
|
+
)
|
159
|
+
):
|
160
|
+
path_keys.add(k)
|
147
161
|
return path_keys
|
148
162
|
|
149
163
|
|
@@ -131,9 +131,15 @@ class ToolsAdapterBase:
|
|
131
131
|
|
132
132
|
if arguments is None:
|
133
133
|
arguments = {}
|
134
|
-
#
|
134
|
+
# If arguments are provided as a non-dict (e.g. a list or a scalar)
|
135
|
+
# we skip signature *keyword* validation completely and defer the
|
136
|
+
# decision to Python's own call mechanics when the function is
|
137
|
+
# eventually invoked. This allows positional / variadic arguments to
|
138
|
+
# be supplied by callers that intentionally bypass the structured
|
139
|
+
# JSON-schema style interface.
|
135
140
|
if not isinstance(arguments, dict):
|
136
|
-
|
141
|
+
# Nothing to validate at this stage – treat as OK.
|
142
|
+
return None
|
137
143
|
|
138
144
|
sig = inspect.signature(func)
|
139
145
|
params = sig.parameters
|
@@ -193,30 +199,32 @@ class ToolsAdapterBase:
|
|
193
199
|
)
|
194
200
|
|
195
201
|
schema = getattr(tool, "schema", None)
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
from janito.report_events import (
|
205
|
-
ReportEvent,
|
206
|
-
ReportSubtype,
|
207
|
-
ReportAction,
|
202
|
+
# Only validate paths for dictionary-style arguments
|
203
|
+
if isinstance(arguments, dict):
|
204
|
+
try:
|
205
|
+
validate_paths_in_arguments(arguments, workdir, schema=schema)
|
206
|
+
except PathSecurityError as sec_err:
|
207
|
+
# Publish both a ToolCallError and a user-facing ReportEvent for path security errors
|
208
|
+
self._publish_tool_call_error(
|
209
|
+
tool_name, request_id, str(sec_err), arguments
|
208
210
|
)
|
211
|
+
if self._event_bus:
|
212
|
+
from janito.report_events import (
|
213
|
+
ReportEvent,
|
214
|
+
ReportSubtype,
|
215
|
+
ReportAction,
|
216
|
+
)
|
209
217
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
218
|
+
self._event_bus.publish(
|
219
|
+
ReportEvent(
|
220
|
+
subtype=ReportSubtype.ERROR,
|
221
|
+
message=f"[SECURITY] Path access denied: {sec_err}",
|
222
|
+
action=ReportAction.EXECUTE,
|
223
|
+
tool=tool_name,
|
224
|
+
context={"arguments": arguments, "request_id": request_id},
|
225
|
+
)
|
217
226
|
)
|
218
|
-
|
219
|
-
return f"Security error: {sec_err}"
|
227
|
+
return f"Security error: {sec_err}"
|
220
228
|
# --- END SECURITY ---
|
221
229
|
|
222
230
|
self._publish_tool_call_started(tool_name, request_id, arguments)
|
@@ -224,7 +232,18 @@ class ToolsAdapterBase:
|
|
224
232
|
f"[tools-adapter] Executing tool: {tool_name} with arguments: {arguments}"
|
225
233
|
)
|
226
234
|
try:
|
227
|
-
|
235
|
+
# Normalize arguments to ensure proper type handling
|
236
|
+
normalized_args = self._normalize_arguments(arguments, tool, func)
|
237
|
+
|
238
|
+
if isinstance(normalized_args, (list, tuple)):
|
239
|
+
# Positional arguments supplied as an array → expand as *args
|
240
|
+
result = self.execute(tool, *normalized_args, **kwargs)
|
241
|
+
elif isinstance(normalized_args, dict) or normalized_args is None:
|
242
|
+
# Keyword-style arguments (the default) – pass as **kwargs
|
243
|
+
result = self.execute(tool, **(normalized_args or {}), **kwargs)
|
244
|
+
else:
|
245
|
+
# Single positional argument (scalar/str/int/…)
|
246
|
+
result = self.execute(tool, normalized_args, **kwargs)
|
228
247
|
except Exception as e:
|
229
248
|
self._handle_execution_error(tool_name, request_id, e, arguments)
|
230
249
|
self._print_verbose(
|
@@ -281,6 +300,65 @@ class ToolsAdapterBase:
|
|
281
300
|
if self.verbose_tools:
|
282
301
|
print(message)
|
283
302
|
|
303
|
+
def _normalize_arguments(self, arguments, tool, func):
|
304
|
+
"""
|
305
|
+
Normalize arguments to ensure proper type handling at the adapter level.
|
306
|
+
|
307
|
+
This handles cases where:
|
308
|
+
1. String is passed instead of list for array parameters
|
309
|
+
2. JSON string parsing issues
|
310
|
+
3. Other type mismatches that can be automatically resolved
|
311
|
+
"""
|
312
|
+
import inspect
|
313
|
+
import json
|
314
|
+
|
315
|
+
# If arguments is already a dict or None, return as-is
|
316
|
+
if isinstance(arguments, dict) or arguments is None:
|
317
|
+
return arguments
|
318
|
+
|
319
|
+
# If arguments is a list/tuple, return as-is (positional args)
|
320
|
+
if isinstance(arguments, (list, tuple)):
|
321
|
+
return arguments
|
322
|
+
|
323
|
+
# Handle string arguments
|
324
|
+
if isinstance(arguments, str):
|
325
|
+
# Try to parse as JSON if it looks like JSON
|
326
|
+
stripped = arguments.strip()
|
327
|
+
if (stripped.startswith('{') and stripped.endswith('}')) or \
|
328
|
+
(stripped.startswith('[') and stripped.endswith(']')):
|
329
|
+
try:
|
330
|
+
parsed = json.loads(arguments)
|
331
|
+
return parsed
|
332
|
+
except json.JSONDecodeError:
|
333
|
+
# If it looks like JSON but failed, try to handle common issues
|
334
|
+
pass
|
335
|
+
|
336
|
+
# Check if the function expects a list parameter
|
337
|
+
try:
|
338
|
+
sig = inspect.signature(func)
|
339
|
+
params = list(sig.parameters.values())
|
340
|
+
|
341
|
+
# Skip 'self' parameter for methods
|
342
|
+
if len(params) > 0 and params[0].name == 'self':
|
343
|
+
params = params[1:]
|
344
|
+
|
345
|
+
# If there's exactly one parameter that expects a list, wrap string in list
|
346
|
+
if len(params) == 1:
|
347
|
+
param = params[0]
|
348
|
+
annotation = param.annotation
|
349
|
+
|
350
|
+
# Check if annotation is list[str] or similar
|
351
|
+
if hasattr(annotation, '__origin__') and annotation.__origin__ is list:
|
352
|
+
return [arguments]
|
353
|
+
elif str(annotation).startswith('list[') or str(annotation) == 'list':
|
354
|
+
return [arguments]
|
355
|
+
|
356
|
+
except (ValueError, TypeError):
|
357
|
+
pass
|
358
|
+
|
359
|
+
# Return original arguments for other cases
|
360
|
+
return arguments
|
361
|
+
|
284
362
|
def execute_function_call_message_part(self, function_call_message_part):
|
285
363
|
"""
|
286
364
|
Execute a FunctionCallMessagePart by extracting the tool name and arguments and dispatching to execute_by_name.
|
@@ -298,9 +376,23 @@ class ToolsAdapterBase:
|
|
298
376
|
# Parse arguments if they are a JSON string
|
299
377
|
if isinstance(arguments, str):
|
300
378
|
try:
|
379
|
+
# Try to parse as JSON first
|
301
380
|
arguments = json.loads(arguments)
|
302
|
-
except
|
303
|
-
|
381
|
+
except json.JSONDecodeError:
|
382
|
+
# Handle single quotes in JSON strings
|
383
|
+
try:
|
384
|
+
# Replace single quotes with double quotes for JSON compatibility
|
385
|
+
fixed_json = arguments.replace("'", '"')
|
386
|
+
arguments = json.loads(fixed_json)
|
387
|
+
except (json.JSONDecodeError, ValueError):
|
388
|
+
# If it's a string that looks like it might be a single path parameter,
|
389
|
+
# try to handle it gracefully
|
390
|
+
if arguments.startswith("{") and arguments.endswith("}"):
|
391
|
+
# Looks like JSON but failed to parse - this is likely an error
|
392
|
+
pass
|
393
|
+
else:
|
394
|
+
# Single string argument - let the normalization handle it
|
395
|
+
pass
|
304
396
|
if self.verbose_tools:
|
305
397
|
print(
|
306
398
|
f"[tools-adapter] Executing FunctionCallMessagePart: tool={tool_name}, arguments={arguments}, tool_call_id={tool_call_id}"
|