code-puppy 0.0.380__tar.gz → 0.0.382__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.
- {code_puppy-0.0.380 → code_puppy-0.0.382}/PKG-INFO +1 -1
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/callbacks.py +70 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/cli_runner.py +93 -1
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/core_commands.py +61 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/motd.py +26 -3
- code_puppy-0.0.382/code_puppy/command_line/wiggum_state.py +78 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/config.py +3 -2
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/model_factory.py +43 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_manager.py +66 -5
- {code_puppy-0.0.380 → code_puppy-0.0.382}/pyproject.toml +1 -1
- code_puppy-0.0.380/code_puppy/plugins/ralph/__init__.py +0 -13
- code_puppy-0.0.380/code_puppy/plugins/ralph/agents.py +0 -433
- code_puppy-0.0.380/code_puppy/plugins/ralph/commands.py +0 -208
- code_puppy-0.0.380/code_puppy/plugins/ralph/loop_controller.py +0 -289
- code_puppy-0.0.380/code_puppy/plugins/ralph/models.py +0 -125
- code_puppy-0.0.380/code_puppy/plugins/ralph/register_callbacks.py +0 -140
- code_puppy-0.0.380/code_puppy/plugins/ralph/state_manager.py +0 -322
- code_puppy-0.0.380/code_puppy/plugins/ralph/tools.py +0 -451
- {code_puppy-0.0.380 → code_puppy-0.0.382}/.gitignore +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/LICENSE +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/README.md +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_helios.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_pack_leader.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_python_programmer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_terminal_qa.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/pack/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/pack/bloodhound.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/pack/husky.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/pack/retriever.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/pack/shepherd.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/pack/terrier.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/pack/watchdog.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/prompt_reviewer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/app.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/main.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/pty_manager.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/routers/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/routers/agents.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/routers/commands.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/routers/config.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/routers/sessions.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/templates/terminal.html +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/api/websocket.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/uc_menu.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/gemini_model.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/main.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/messaging/subagent_console.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/model_switching.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/models.json +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/transport.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/antigravity_oauth/utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/universal_constructor/models.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/universal_constructor/registry.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/prompts/antigravity_system_prompt.md +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/chromium_terminal_manager.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/terminal_command_tools.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/terminal_screenshot_tools.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/browser/terminal_tools.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/tools/universal_constructor.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/uvx_detection.py +0 -0
- {code_puppy-0.0.380 → code_puppy-0.0.382}/code_puppy/version_checker.py +0 -0
|
@@ -13,6 +13,7 @@ PhaseType = Literal[
|
|
|
13
13
|
"delete_file",
|
|
14
14
|
"run_shell_command",
|
|
15
15
|
"load_model_config",
|
|
16
|
+
"load_models_config",
|
|
16
17
|
"load_prompt",
|
|
17
18
|
"agent_reload",
|
|
18
19
|
"custom_command",
|
|
@@ -28,6 +29,9 @@ PhaseType = Literal[
|
|
|
28
29
|
"agent_run_start",
|
|
29
30
|
"agent_run_end",
|
|
30
31
|
"register_mcp_catalog_servers",
|
|
32
|
+
"register_browser_types",
|
|
33
|
+
"get_motd",
|
|
34
|
+
"register_model_providers",
|
|
31
35
|
]
|
|
32
36
|
CallbackFunc = Callable[..., Any]
|
|
33
37
|
|
|
@@ -41,6 +45,7 @@ _callbacks: Dict[PhaseType, List[CallbackFunc]] = {
|
|
|
41
45
|
"delete_file": [],
|
|
42
46
|
"run_shell_command": [],
|
|
43
47
|
"load_model_config": [],
|
|
48
|
+
"load_models_config": [],
|
|
44
49
|
"load_prompt": [],
|
|
45
50
|
"agent_reload": [],
|
|
46
51
|
"custom_command": [],
|
|
@@ -56,6 +61,9 @@ _callbacks: Dict[PhaseType, List[CallbackFunc]] = {
|
|
|
56
61
|
"agent_run_start": [],
|
|
57
62
|
"agent_run_end": [],
|
|
58
63
|
"register_mcp_catalog_servers": [],
|
|
64
|
+
"register_browser_types": [],
|
|
65
|
+
"get_motd": [],
|
|
66
|
+
"register_model_providers": [],
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
logger = logging.getLogger(__name__)
|
|
@@ -206,6 +214,19 @@ def on_load_model_config(*args, **kwargs) -> List[Any]:
|
|
|
206
214
|
return _trigger_callbacks_sync("load_model_config", *args, **kwargs)
|
|
207
215
|
|
|
208
216
|
|
|
217
|
+
def on_load_models_config() -> List[Any]:
|
|
218
|
+
"""Trigger callbacks to load additional model configurations.
|
|
219
|
+
|
|
220
|
+
Plugins can register callbacks that return a dict of model configurations
|
|
221
|
+
to be merged with the built-in models.json. Plugin models override built-in
|
|
222
|
+
models with the same name.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
List of model config dicts from all registered callbacks.
|
|
226
|
+
"""
|
|
227
|
+
return _trigger_callbacks_sync("load_models_config")
|
|
228
|
+
|
|
229
|
+
|
|
209
230
|
def on_edit_file(*args, **kwargs) -> Any:
|
|
210
231
|
return _trigger_callbacks_sync("edit_file", *args, **kwargs)
|
|
211
232
|
|
|
@@ -531,3 +552,52 @@ def on_register_mcp_catalog_servers() -> List[Any]:
|
|
|
531
552
|
List of results from all registered callbacks (each should be a list of MCPServerTemplate).
|
|
532
553
|
"""
|
|
533
554
|
return _trigger_callbacks_sync("register_mcp_catalog_servers")
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def on_register_browser_types() -> List[Any]:
|
|
558
|
+
"""Trigger callbacks to register custom browser types/providers.
|
|
559
|
+
|
|
560
|
+
Plugins can register callbacks that return a dict mapping browser type names
|
|
561
|
+
to initialization functions. This allows plugins to provide custom browser
|
|
562
|
+
implementations (like Camoufox for stealth browsing).
|
|
563
|
+
|
|
564
|
+
Each callback should return a dict with:
|
|
565
|
+
- key: str - the browser type name (e.g., "camoufox", "firefox-stealth")
|
|
566
|
+
- value: callable - async initialization function that takes (manager, **kwargs)
|
|
567
|
+
and sets up the browser on the manager instance
|
|
568
|
+
|
|
569
|
+
Example callback:
|
|
570
|
+
def register_my_browser_types():
|
|
571
|
+
return {
|
|
572
|
+
"camoufox": initialize_camoufox,
|
|
573
|
+
"my-stealth-browser": initialize_my_stealth,
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
Returns:
|
|
577
|
+
List of dicts from all registered callbacks.
|
|
578
|
+
"""
|
|
579
|
+
return _trigger_callbacks_sync("register_browser_types")
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def on_get_motd() -> List[Any]:
|
|
583
|
+
"""Trigger callbacks to get custom MOTD content.
|
|
584
|
+
|
|
585
|
+
Plugins can register callbacks that return a tuple of (message, version).
|
|
586
|
+
The last non-None result will be used as the MOTD.
|
|
587
|
+
|
|
588
|
+
Returns:
|
|
589
|
+
List of (message, version) tuples from registered callbacks.
|
|
590
|
+
"""
|
|
591
|
+
return _trigger_callbacks_sync("get_motd")
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def on_register_model_providers() -> List[Any]:
|
|
595
|
+
"""Trigger callbacks to register custom model provider classes.
|
|
596
|
+
|
|
597
|
+
Plugins can register callbacks that return a dict mapping provider names
|
|
598
|
+
to model classes. Example: {"walmart_gemini": WalmartGeminiModel}
|
|
599
|
+
|
|
600
|
+
Returns:
|
|
601
|
+
List of dicts from all registered callbacks.
|
|
602
|
+
"""
|
|
603
|
+
return _trigger_callbacks_sync("register_model_providers")
|
|
@@ -551,7 +551,13 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
551
551
|
reset_windows_terminal_full()
|
|
552
552
|
from code_puppy.messaging import emit_warning
|
|
553
553
|
|
|
554
|
-
|
|
554
|
+
# Stop wiggum mode on Ctrl+C
|
|
555
|
+
from code_puppy.command_line.wiggum_state import is_wiggum_active, stop_wiggum
|
|
556
|
+
if is_wiggum_active():
|
|
557
|
+
stop_wiggum()
|
|
558
|
+
emit_warning("\n🍩 Wiggum loop stopped!")
|
|
559
|
+
else:
|
|
560
|
+
emit_warning("\nInput cancelled")
|
|
555
561
|
continue
|
|
556
562
|
|
|
557
563
|
# Check for exit commands (plain text or command form)
|
|
@@ -718,6 +724,12 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
718
724
|
ensure_ctrl_c_disabled()
|
|
719
725
|
except ImportError:
|
|
720
726
|
pass
|
|
727
|
+
# Stop wiggum mode on cancellation
|
|
728
|
+
from code_puppy.command_line.wiggum_state import is_wiggum_active, stop_wiggum
|
|
729
|
+
if is_wiggum_active():
|
|
730
|
+
stop_wiggum()
|
|
731
|
+
from code_puppy.messaging import emit_warning
|
|
732
|
+
emit_warning("🍩 Wiggum loop stopped due to cancellation")
|
|
721
733
|
continue
|
|
722
734
|
# Get the structured response
|
|
723
735
|
agent_response = result.output
|
|
@@ -758,6 +770,86 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
758
770
|
|
|
759
771
|
auto_save_session_if_enabled()
|
|
760
772
|
|
|
773
|
+
# ================================================================
|
|
774
|
+
# WIGGUM LOOP: Re-run prompt if wiggum mode is active
|
|
775
|
+
# ================================================================
|
|
776
|
+
from code_puppy.command_line.wiggum_state import (
|
|
777
|
+
get_wiggum_prompt,
|
|
778
|
+
get_wiggum_count,
|
|
779
|
+
increment_wiggum_count,
|
|
780
|
+
is_wiggum_active,
|
|
781
|
+
stop_wiggum,
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
while is_wiggum_active():
|
|
785
|
+
wiggum_prompt = get_wiggum_prompt()
|
|
786
|
+
if not wiggum_prompt:
|
|
787
|
+
stop_wiggum()
|
|
788
|
+
break
|
|
789
|
+
|
|
790
|
+
# Increment and show debug message
|
|
791
|
+
loop_num = increment_wiggum_count()
|
|
792
|
+
from code_puppy.messaging import emit_warning, emit_system_message
|
|
793
|
+
|
|
794
|
+
emit_warning(f"\n🍩 WIGGUM RELOOPING! (Loop #{loop_num})")
|
|
795
|
+
emit_system_message(f"Re-running prompt: {wiggum_prompt}")
|
|
796
|
+
|
|
797
|
+
# Reset context/history for fresh start
|
|
798
|
+
new_session_id = finalize_autosave_session()
|
|
799
|
+
current_agent.clear_message_history()
|
|
800
|
+
emit_system_message(f"Context cleared. Session rotated to: {new_session_id}")
|
|
801
|
+
|
|
802
|
+
# Small delay to let user see the debug message
|
|
803
|
+
import time
|
|
804
|
+
time.sleep(0.5)
|
|
805
|
+
|
|
806
|
+
try:
|
|
807
|
+
# Re-run the wiggum prompt
|
|
808
|
+
result, current_agent_task = await run_prompt_with_attachments(
|
|
809
|
+
current_agent,
|
|
810
|
+
wiggum_prompt,
|
|
811
|
+
spinner_console=message_renderer.console,
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
if result is None:
|
|
815
|
+
# Cancelled - stop wiggum mode
|
|
816
|
+
emit_warning("Wiggum loop cancelled by user")
|
|
817
|
+
stop_wiggum()
|
|
818
|
+
break
|
|
819
|
+
|
|
820
|
+
# Get the structured response
|
|
821
|
+
agent_response = result.output
|
|
822
|
+
|
|
823
|
+
# Emit structured message for proper markdown rendering
|
|
824
|
+
response_msg = AgentResponseMessage(
|
|
825
|
+
content=agent_response,
|
|
826
|
+
is_markdown=True,
|
|
827
|
+
)
|
|
828
|
+
get_message_bus().emit(response_msg)
|
|
829
|
+
|
|
830
|
+
# Update message history
|
|
831
|
+
if hasattr(result, "all_messages"):
|
|
832
|
+
current_agent.set_message_history(list(result.all_messages()))
|
|
833
|
+
|
|
834
|
+
# Flush console
|
|
835
|
+
display_console.file.flush() if hasattr(
|
|
836
|
+
display_console.file, "flush"
|
|
837
|
+
) else None
|
|
838
|
+
time.sleep(0.1)
|
|
839
|
+
|
|
840
|
+
# Auto-save
|
|
841
|
+
auto_save_session_if_enabled()
|
|
842
|
+
|
|
843
|
+
except KeyboardInterrupt:
|
|
844
|
+
emit_warning("\n🍩 Wiggum loop interrupted by Ctrl+C")
|
|
845
|
+
stop_wiggum()
|
|
846
|
+
break
|
|
847
|
+
except Exception as e:
|
|
848
|
+
from code_puppy.messaging import emit_error
|
|
849
|
+
emit_error(f"Wiggum loop error: {e}")
|
|
850
|
+
stop_wiggum()
|
|
851
|
+
break
|
|
852
|
+
|
|
761
853
|
# Re-disable Ctrl+C if needed (uvx mode) - must be done after
|
|
762
854
|
# each iteration as various operations may restore console mode
|
|
763
855
|
try:
|
|
@@ -790,3 +790,64 @@ def handle_generate_pr_description_command(command: str) -> str:
|
|
|
790
790
|
|
|
791
791
|
# Return the prompt to be processed by the main chat system
|
|
792
792
|
return pr_prompt
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
@register_command(
|
|
796
|
+
name="wiggum",
|
|
797
|
+
description="Loop mode: re-run the same prompt when agent finishes (like Wiggum chasing donuts 🍩)",
|
|
798
|
+
usage="/wiggum <prompt>",
|
|
799
|
+
category="core",
|
|
800
|
+
)
|
|
801
|
+
def handle_wiggum_command(command: str) -> str | bool:
|
|
802
|
+
"""Start wiggum loop mode.
|
|
803
|
+
|
|
804
|
+
When active, the agent will automatically re-run the same prompt
|
|
805
|
+
after completing, resetting context each time. Use Ctrl+C to stop.
|
|
806
|
+
|
|
807
|
+
Example:
|
|
808
|
+
/wiggum say hello world
|
|
809
|
+
"""
|
|
810
|
+
from code_puppy.command_line.wiggum_state import start_wiggum, stop_wiggum
|
|
811
|
+
from code_puppy.messaging import emit_info, emit_success, emit_warning
|
|
812
|
+
|
|
813
|
+
# Extract the prompt after /wiggum
|
|
814
|
+
parts = command.split(maxsplit=1)
|
|
815
|
+
if len(parts) < 2 or not parts[1].strip():
|
|
816
|
+
emit_warning("Usage: /wiggum <prompt>")
|
|
817
|
+
emit_info("Example: /wiggum say hello world")
|
|
818
|
+
emit_info("This will repeatedly run 'say hello world' after each completion.")
|
|
819
|
+
emit_info("Press Ctrl+C to stop the loop.")
|
|
820
|
+
return True
|
|
821
|
+
|
|
822
|
+
prompt = parts[1].strip()
|
|
823
|
+
|
|
824
|
+
# Start wiggum mode
|
|
825
|
+
start_wiggum(prompt)
|
|
826
|
+
emit_success(f"🍩 WIGGUM MODE ACTIVATED!")
|
|
827
|
+
emit_info(f"Prompt: {prompt}")
|
|
828
|
+
emit_info("The agent will re-loop this prompt after each completion.")
|
|
829
|
+
emit_info("Press Ctrl+C to stop the wiggum loop.")
|
|
830
|
+
|
|
831
|
+
# Return the prompt to execute immediately
|
|
832
|
+
return prompt
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
@register_command(
|
|
836
|
+
name="wiggum_stop",
|
|
837
|
+
description="Stop wiggum loop mode",
|
|
838
|
+
usage="/wiggum_stop",
|
|
839
|
+
aliases=["stopwiggum", "ws"],
|
|
840
|
+
category="core",
|
|
841
|
+
)
|
|
842
|
+
def handle_wiggum_stop_command(command: str) -> bool:
|
|
843
|
+
"""Stop wiggum loop mode."""
|
|
844
|
+
from code_puppy.command_line.wiggum_state import is_wiggum_active, stop_wiggum
|
|
845
|
+
from code_puppy.messaging import emit_info, emit_success
|
|
846
|
+
|
|
847
|
+
if is_wiggum_active():
|
|
848
|
+
stop_wiggum()
|
|
849
|
+
emit_success("🍩 Wiggum mode stopped!")
|
|
850
|
+
else:
|
|
851
|
+
emit_info("Wiggum mode is not active.")
|
|
852
|
+
|
|
853
|
+
return True
|
|
@@ -25,6 +25,28 @@ Reminder that Code Puppy supports three different OAuth subscriptions:
|
|
|
25
25
|
MOTD_TRACK_FILE = os.path.join(CONFIG_DIR, "motd.txt")
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def get_motd_content() -> tuple[str, str]:
|
|
29
|
+
"""Get MOTD content, checking plugins first.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Tuple of (message, version) - either from plugin or built-in.
|
|
33
|
+
"""
|
|
34
|
+
# Check if plugins want to override MOTD
|
|
35
|
+
try:
|
|
36
|
+
from code_puppy.callbacks import on_get_motd
|
|
37
|
+
|
|
38
|
+
results = on_get_motd()
|
|
39
|
+
# Use the last non-None result
|
|
40
|
+
for result in reversed(results):
|
|
41
|
+
if result is not None and isinstance(result, tuple) and len(result) == 2:
|
|
42
|
+
return result
|
|
43
|
+
except Exception:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
# Fall back to built-in MOTD
|
|
47
|
+
return (MOTD_MESSAGE, MOTD_VERSION)
|
|
48
|
+
|
|
49
|
+
|
|
28
50
|
def has_seen_motd(version: str) -> bool: # 🐕 Check if puppy has seen this MOTD!
|
|
29
51
|
if not os.path.exists(MOTD_TRACK_FILE):
|
|
30
52
|
return False
|
|
@@ -62,12 +84,13 @@ def print_motd(
|
|
|
62
84
|
Returns:
|
|
63
85
|
True if the MOTD was printed, False otherwise 🐾
|
|
64
86
|
"""
|
|
65
|
-
|
|
87
|
+
message, version = get_motd_content()
|
|
88
|
+
if force or not has_seen_motd(version):
|
|
66
89
|
# Create a Rich Markdown object for proper rendering 🎨🐶
|
|
67
90
|
from rich.markdown import Markdown
|
|
68
91
|
|
|
69
|
-
markdown_content = Markdown(
|
|
92
|
+
markdown_content = Markdown(message)
|
|
70
93
|
emit_info(markdown_content)
|
|
71
|
-
mark_motd_seen(
|
|
94
|
+
mark_motd_seen(version)
|
|
72
95
|
return True
|
|
73
96
|
return False
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Wiggum loop state management.
|
|
2
|
+
|
|
3
|
+
This module tracks the state for the /wiggum command, which causes
|
|
4
|
+
the agent to automatically re-run the same prompt after completing,
|
|
5
|
+
like Chief Wiggum chasing donuts in circles. 🍩
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
/wiggum <prompt> - Start looping with the given prompt
|
|
9
|
+
Ctrl+C - Stop the wiggum loop
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class WiggumState:
|
|
18
|
+
"""State container for wiggum loop mode."""
|
|
19
|
+
|
|
20
|
+
active: bool = False
|
|
21
|
+
prompt: Optional[str] = None
|
|
22
|
+
loop_count: int = 0
|
|
23
|
+
|
|
24
|
+
def start(self, prompt: str) -> None:
|
|
25
|
+
"""Start wiggum mode with the given prompt."""
|
|
26
|
+
self.active = True
|
|
27
|
+
self.prompt = prompt
|
|
28
|
+
self.loop_count = 0
|
|
29
|
+
|
|
30
|
+
def stop(self) -> None:
|
|
31
|
+
"""Stop wiggum mode."""
|
|
32
|
+
self.active = False
|
|
33
|
+
self.prompt = None
|
|
34
|
+
self.loop_count = 0
|
|
35
|
+
|
|
36
|
+
def increment(self) -> int:
|
|
37
|
+
"""Increment and return the loop count."""
|
|
38
|
+
self.loop_count += 1
|
|
39
|
+
return self.loop_count
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Global singleton for wiggum state
|
|
43
|
+
_wiggum_state = WiggumState()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_wiggum_state() -> WiggumState:
|
|
47
|
+
"""Get the global wiggum state."""
|
|
48
|
+
return _wiggum_state
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def is_wiggum_active() -> bool:
|
|
52
|
+
"""Check if wiggum mode is currently active."""
|
|
53
|
+
return _wiggum_state.active
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_wiggum_prompt() -> Optional[str]:
|
|
57
|
+
"""Get the current wiggum prompt, if active."""
|
|
58
|
+
return _wiggum_state.prompt if _wiggum_state.active else None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def start_wiggum(prompt: str) -> None:
|
|
62
|
+
"""Start wiggum mode with the given prompt."""
|
|
63
|
+
_wiggum_state.start(prompt)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def stop_wiggum() -> None:
|
|
67
|
+
"""Stop wiggum mode."""
|
|
68
|
+
_wiggum_state.stop()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def increment_wiggum_count() -> int:
|
|
72
|
+
"""Increment wiggum loop count and return the new value."""
|
|
73
|
+
return _wiggum_state.increment()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_wiggum_count() -> int:
|
|
77
|
+
"""Get the current wiggum loop count."""
|
|
78
|
+
return _wiggum_state.loop_count
|
|
@@ -715,8 +715,9 @@ def set_model_setting(model_name: str, setting: str, value: Optional[float]) ->
|
|
|
715
715
|
if value is None:
|
|
716
716
|
set_config_value(key, "")
|
|
717
717
|
elif isinstance(value, float):
|
|
718
|
-
# Round floats to nearest
|
|
719
|
-
|
|
718
|
+
# Round floats to nearest hundredth to avoid floating point weirdness
|
|
719
|
+
# (allows 0.05 step increments for temperature/top_p)
|
|
720
|
+
set_config_value(key, str(round(value, 2)))
|
|
720
721
|
else:
|
|
721
722
|
set_config_value(key, str(value))
|
|
722
723
|
|
|
@@ -30,6 +30,26 @@ from .round_robin_model import RoundRobinModel
|
|
|
30
30
|
|
|
31
31
|
logger = logging.getLogger(__name__)
|
|
32
32
|
|
|
33
|
+
# Registry for custom model provider classes from plugins
|
|
34
|
+
_CUSTOM_MODEL_PROVIDERS: Dict[str, type] = {}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _load_plugin_model_providers():
|
|
38
|
+
"""Load custom model providers from plugins."""
|
|
39
|
+
global _CUSTOM_MODEL_PROVIDERS
|
|
40
|
+
try:
|
|
41
|
+
from code_puppy.callbacks import on_register_model_providers
|
|
42
|
+
results = on_register_model_providers()
|
|
43
|
+
for result in results:
|
|
44
|
+
if isinstance(result, dict):
|
|
45
|
+
_CUSTOM_MODEL_PROVIDERS.update(result)
|
|
46
|
+
except Exception:
|
|
47
|
+
pass # Don't break if plugins fail
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Load plugin model providers at module initialization
|
|
51
|
+
_load_plugin_model_providers()
|
|
52
|
+
|
|
33
53
|
|
|
34
54
|
def get_api_key(env_var_name: str) -> str | None:
|
|
35
55
|
"""Get an API key from config first, then fall back to environment variable.
|
|
@@ -279,6 +299,20 @@ class ModelFactory:
|
|
|
279
299
|
logging.getLogger(__name__).warning(
|
|
280
300
|
f"Failed to load {label} config from {source_path}: {exc}"
|
|
281
301
|
)
|
|
302
|
+
|
|
303
|
+
# Let plugins add/override models via load_models_config hook
|
|
304
|
+
try:
|
|
305
|
+
from code_puppy.callbacks import on_load_models_config
|
|
306
|
+
|
|
307
|
+
results = on_load_models_config()
|
|
308
|
+
for result in results:
|
|
309
|
+
if isinstance(result, dict):
|
|
310
|
+
config.update(result) # Plugin models override built-in
|
|
311
|
+
except Exception as exc:
|
|
312
|
+
logging.getLogger(__name__).debug(
|
|
313
|
+
f"Failed to load plugin models config: {exc}"
|
|
314
|
+
)
|
|
315
|
+
|
|
282
316
|
return config
|
|
283
317
|
|
|
284
318
|
@staticmethod
|
|
@@ -294,6 +328,15 @@ class ModelFactory:
|
|
|
294
328
|
|
|
295
329
|
model_type = model_config.get("type")
|
|
296
330
|
|
|
331
|
+
# Check for plugin-registered model provider classes first
|
|
332
|
+
if model_type in _CUSTOM_MODEL_PROVIDERS:
|
|
333
|
+
provider_class = _CUSTOM_MODEL_PROVIDERS[model_type]
|
|
334
|
+
try:
|
|
335
|
+
return provider_class(model_name=model_name, model_config=model_config, config=config)
|
|
336
|
+
except Exception as e:
|
|
337
|
+
logger.error(f"Custom model provider '{model_type}' failed: {e}")
|
|
338
|
+
return None
|
|
339
|
+
|
|
297
340
|
if model_type == "gemini":
|
|
298
341
|
api_key = get_api_key("GEMINI_API_KEY")
|
|
299
342
|
if not api_key:
|
|
@@ -8,13 +8,41 @@ import atexit
|
|
|
8
8
|
import contextvars
|
|
9
9
|
import os
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Optional
|
|
11
|
+
from typing import Callable, Dict, Optional
|
|
12
12
|
|
|
13
13
|
from playwright.async_api import Browser, BrowserContext, Page
|
|
14
14
|
|
|
15
15
|
from code_puppy import config
|
|
16
16
|
from code_puppy.messaging import emit_info, emit_success, emit_warning
|
|
17
17
|
|
|
18
|
+
# Registry for custom browser types from plugins (e.g., Camoufox for stealth browsing)
|
|
19
|
+
_CUSTOM_BROWSER_TYPES: Dict[str, Callable] = {}
|
|
20
|
+
_BROWSER_TYPES_LOADED: bool = False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _load_plugin_browser_types() -> None:
|
|
24
|
+
"""Load custom browser types from plugins.
|
|
25
|
+
|
|
26
|
+
This is called lazily on first browser initialization to allow plugins
|
|
27
|
+
to register custom browser providers (like Camoufox for stealth browsing).
|
|
28
|
+
"""
|
|
29
|
+
global _CUSTOM_BROWSER_TYPES, _BROWSER_TYPES_LOADED
|
|
30
|
+
|
|
31
|
+
if _BROWSER_TYPES_LOADED:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
_BROWSER_TYPES_LOADED = True
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from code_puppy.callbacks import on_register_browser_types
|
|
38
|
+
|
|
39
|
+
results = on_register_browser_types()
|
|
40
|
+
for result in results:
|
|
41
|
+
if isinstance(result, dict):
|
|
42
|
+
_CUSTOM_BROWSER_TYPES.update(result)
|
|
43
|
+
except Exception:
|
|
44
|
+
pass # Don't break if plugins fail to load
|
|
45
|
+
|
|
18
46
|
# Store active manager instances by session ID
|
|
19
47
|
_active_managers: dict[str, "BrowserManager"] = {}
|
|
20
48
|
|
|
@@ -78,14 +106,19 @@ class BrowserManager:
|
|
|
78
106
|
_context: Optional[BrowserContext] = None
|
|
79
107
|
_initialized: bool = False
|
|
80
108
|
|
|
81
|
-
def __init__(
|
|
109
|
+
def __init__(
|
|
110
|
+
self, session_id: Optional[str] = None, browser_type: Optional[str] = None
|
|
111
|
+
):
|
|
82
112
|
"""Initialize manager settings.
|
|
83
113
|
|
|
84
114
|
Args:
|
|
85
115
|
session_id: Optional session ID for this instance.
|
|
86
116
|
If None, uses 'default' as the session ID.
|
|
117
|
+
browser_type: Optional browser type to use. If None, uses Chromium.
|
|
118
|
+
Custom types can be registered via the register_browser_types hook.
|
|
87
119
|
"""
|
|
88
120
|
self.session_id = session_id or "default"
|
|
121
|
+
self.browser_type = browser_type # None means default Chromium
|
|
89
122
|
|
|
90
123
|
# Default to headless=True (no browser spam during tests)
|
|
91
124
|
# Override with BROWSER_HEADLESS=false to see the browser
|
|
@@ -124,7 +157,27 @@ class BrowserManager:
|
|
|
124
157
|
raise
|
|
125
158
|
|
|
126
159
|
async def _initialize_browser(self) -> None:
|
|
127
|
-
"""Initialize
|
|
160
|
+
"""Initialize browser with persistent context.
|
|
161
|
+
|
|
162
|
+
Checks for custom browser types registered via plugins first,
|
|
163
|
+
then falls back to default Playwright Chromium.
|
|
164
|
+
"""
|
|
165
|
+
# Load plugin browser types on first initialization
|
|
166
|
+
_load_plugin_browser_types()
|
|
167
|
+
|
|
168
|
+
# Check if a custom browser type was requested and is available
|
|
169
|
+
if self.browser_type and self.browser_type in _CUSTOM_BROWSER_TYPES:
|
|
170
|
+
emit_info(
|
|
171
|
+
f"Using custom browser type '{self.browser_type}' "
|
|
172
|
+
f"(session: {self.session_id})"
|
|
173
|
+
)
|
|
174
|
+
init_func = _CUSTOM_BROWSER_TYPES[self.browser_type]
|
|
175
|
+
# Custom init functions should set self._context and self._browser
|
|
176
|
+
await init_func(self)
|
|
177
|
+
self._initialized = True
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
# Default: use Playwright Chromium
|
|
128
181
|
from playwright.async_api import async_playwright
|
|
129
182
|
|
|
130
183
|
emit_info(f"Using persistent profile: {self.profile_dir}")
|
|
@@ -220,13 +273,18 @@ class BrowserManager:
|
|
|
220
273
|
emit_info(f"Browser closed (session: {self.session_id})")
|
|
221
274
|
|
|
222
275
|
|
|
223
|
-
def get_browser_manager(
|
|
276
|
+
def get_browser_manager(
|
|
277
|
+
session_id: Optional[str] = None, browser_type: Optional[str] = None
|
|
278
|
+
) -> BrowserManager:
|
|
224
279
|
"""Get or create a BrowserManager instance.
|
|
225
280
|
|
|
226
281
|
Args:
|
|
227
282
|
session_id: Optional session ID. If provided and a manager with this
|
|
228
283
|
session exists, returns that manager. Otherwise creates a new one.
|
|
229
284
|
If None, uses 'default' as the session ID.
|
|
285
|
+
browser_type: Optional browser type to use for new managers.
|
|
286
|
+
Ignored if a manager for this session already exists.
|
|
287
|
+
Custom types can be registered via the register_browser_types hook.
|
|
230
288
|
|
|
231
289
|
Returns:
|
|
232
290
|
A BrowserManager instance.
|
|
@@ -237,11 +295,14 @@ def get_browser_manager(session_id: Optional[str] = None) -> BrowserManager:
|
|
|
237
295
|
|
|
238
296
|
# Named session (for multi-agent use)
|
|
239
297
|
manager = get_browser_manager("qa-agent-1")
|
|
298
|
+
|
|
299
|
+
# Custom browser type (e.g., stealth browser from plugin)
|
|
300
|
+
manager = get_browser_manager("stealth-session", browser_type="camoufox")
|
|
240
301
|
"""
|
|
241
302
|
session_id = session_id or "default"
|
|
242
303
|
|
|
243
304
|
if session_id not in _active_managers:
|
|
244
|
-
_active_managers[session_id] = BrowserManager(session_id)
|
|
305
|
+
_active_managers[session_id] = BrowserManager(session_id, browser_type)
|
|
245
306
|
|
|
246
307
|
return _active_managers[session_id]
|
|
247
308
|
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"""Ralph Plugin - Autonomous AI agent loop for completing PRDs.
|
|
2
|
-
|
|
3
|
-
Based on Geoffrey Huntley's Ralph pattern: https://ghuntley.com/ralph/
|
|
4
|
-
|
|
5
|
-
This plugin provides:
|
|
6
|
-
- PRD Generator agent for creating detailed requirements
|
|
7
|
-
- Ralph Converter agent for converting PRDs to JSON format
|
|
8
|
-
- Ralph Orchestrator agent for autonomous execution
|
|
9
|
-
- Tools for managing prd.json and progress.txt
|
|
10
|
-
- /ralph commands for controlling the workflow
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
__version__ = "0.1.0"
|