code-puppy 0.0.375__tar.gz → 0.0.377__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.375 → code_puppy-0.0.377}/PKG-INFO +1 -1
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/base_agent.py +88 -64
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/callbacks.py +57 -9
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/model_settings_menu.py +13 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/gemini_model.py +63 -22
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/model_factory.py +13 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/models.json +2 -2
- code_puppy-0.0.377/code_puppy/plugins/claude_code_oauth/__init__.py +25 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +72 -0
- code_puppy-0.0.377/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +242 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/loop_controller.py +52 -48
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/register_callbacks.py +13 -6
- {code_puppy-0.0.375 → code_puppy-0.0.377}/pyproject.toml +1 -1
- code_puppy-0.0.375/code_puppy/plugins/claude_code_oauth/__init__.py +0 -6
- {code_puppy-0.0.375 → code_puppy-0.0.377}/.gitignore +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/LICENSE +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/README.md +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_helios.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_pack_leader.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_python_programmer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_terminal_qa.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/pack/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/pack/bloodhound.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/pack/husky.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/pack/retriever.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/pack/shepherd.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/pack/terrier.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/pack/watchdog.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/prompt_reviewer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/app.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/main.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/pty_manager.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/routers/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/routers/agents.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/routers/commands.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/routers/config.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/routers/sessions.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/templates/terminal.html +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/api/websocket.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/cli_runner.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/uc_menu.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/config.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/main.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/messaging/subagent_console.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/model_switching.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/transport.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/antigravity_oauth/utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/agents.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/commands.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/models.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/state_manager.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/ralph/tools.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/universal_constructor/models.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/universal_constructor/registry.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/prompts/antigravity_system_prompt.md +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_manager.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/chromium_terminal_manager.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/terminal_command_tools.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/terminal_screenshot_tools.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/browser/terminal_tools.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/tools/universal_constructor.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/uvx_detection.py +0 -0
- {code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/version_checker.py +0 -0
|
@@ -47,7 +47,10 @@ from pydantic_ai.messages import (
|
|
|
47
47
|
from rich.text import Text
|
|
48
48
|
|
|
49
49
|
from code_puppy.agents.event_stream_handler import event_stream_handler
|
|
50
|
-
from code_puppy.callbacks import
|
|
50
|
+
from code_puppy.callbacks import (
|
|
51
|
+
on_agent_run_end,
|
|
52
|
+
on_agent_run_start,
|
|
53
|
+
)
|
|
51
54
|
|
|
52
55
|
# Consolidated relative imports
|
|
53
56
|
from code_puppy.config import (
|
|
@@ -404,35 +407,27 @@ class BaseAgent(ABC):
|
|
|
404
407
|
total_tokens = 0
|
|
405
408
|
|
|
406
409
|
# 1. Estimate tokens for system prompt / instructions
|
|
407
|
-
#
|
|
408
|
-
#
|
|
409
|
-
# fixed instructions. For other models,
|
|
410
|
+
# Use prepare_prompt_for_model() to get the correct instructions for token counting.
|
|
411
|
+
# For models that prepend system prompt to user message (claude-code, antigravity),
|
|
412
|
+
# this returns the short fixed instructions. For other models, returns full prompt.
|
|
410
413
|
try:
|
|
411
|
-
from code_puppy.model_utils import
|
|
412
|
-
get_antigravity_instructions,
|
|
413
|
-
get_claude_code_instructions,
|
|
414
|
-
is_antigravity_model,
|
|
415
|
-
is_claude_code_model,
|
|
416
|
-
)
|
|
414
|
+
from code_puppy.model_utils import prepare_prompt_for_model
|
|
417
415
|
|
|
418
416
|
model_name = (
|
|
419
417
|
self.get_model_name() if hasattr(self, "get_model_name") else ""
|
|
420
418
|
)
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
system_prompt = self.get_full_system_prompt()
|
|
434
|
-
if system_prompt:
|
|
435
|
-
total_tokens += self.estimate_token_count(system_prompt)
|
|
419
|
+
system_prompt = self.get_full_system_prompt()
|
|
420
|
+
|
|
421
|
+
# Get the instructions that will be used (handles model-specific logic via hooks)
|
|
422
|
+
prepared = prepare_prompt_for_model(
|
|
423
|
+
model_name=model_name,
|
|
424
|
+
system_prompt=system_prompt,
|
|
425
|
+
user_prompt="", # Empty - we just need the instructions
|
|
426
|
+
prepend_system_to_user=False, # Don't modify prompt, just get instructions
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
if prepared.instructions:
|
|
430
|
+
total_tokens += self.estimate_token_count(prepared.instructions)
|
|
436
431
|
except Exception:
|
|
437
432
|
pass # If we can't get system prompt, skip it
|
|
438
433
|
|
|
@@ -1590,21 +1585,25 @@ class BaseAgent(ABC):
|
|
|
1590
1585
|
if output_type is not None:
|
|
1591
1586
|
pydantic_agent = self._create_agent_with_output_type(output_type)
|
|
1592
1587
|
|
|
1593
|
-
# Handle
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
is_claude_code_model,
|
|
1597
|
-
)
|
|
1588
|
+
# Handle model-specific prompt transformations via prepare_prompt_for_model()
|
|
1589
|
+
# This uses the get_model_system_prompt hook, so plugins can register their own handlers
|
|
1590
|
+
from code_puppy.model_utils import prepare_prompt_for_model
|
|
1598
1591
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1592
|
+
# Only prepend system prompt on first message (empty history)
|
|
1593
|
+
should_prepend = len(self.get_message_history()) == 0
|
|
1594
|
+
if should_prepend:
|
|
1595
|
+
system_prompt = self.get_full_system_prompt()
|
|
1596
|
+
puppy_rules = self.load_puppy_rules()
|
|
1597
|
+
if puppy_rules:
|
|
1598
|
+
system_prompt += f"\n{puppy_rules}"
|
|
1599
|
+
|
|
1600
|
+
prepared = prepare_prompt_for_model(
|
|
1601
|
+
model_name=self.get_model_name(),
|
|
1602
|
+
system_prompt=system_prompt,
|
|
1603
|
+
user_prompt=prompt,
|
|
1604
|
+
prepend_system_to_user=True,
|
|
1605
|
+
)
|
|
1606
|
+
prompt = prepared.user_prompt
|
|
1608
1607
|
|
|
1609
1608
|
# Build combined prompt payload when attachments are provided.
|
|
1610
1609
|
attachment_parts: List[Any] = []
|
|
@@ -1751,6 +1750,17 @@ class BaseAgent(ABC):
|
|
|
1751
1750
|
# Create the task FIRST
|
|
1752
1751
|
agent_task = asyncio.create_task(run_agent_task())
|
|
1753
1752
|
|
|
1753
|
+
# Fire agent_run_start hook - plugins can use this to start background tasks
|
|
1754
|
+
# (e.g., token refresh heartbeats for OAuth models)
|
|
1755
|
+
try:
|
|
1756
|
+
await on_agent_run_start(
|
|
1757
|
+
agent_name=self.name,
|
|
1758
|
+
model_name=self.get_model_name(),
|
|
1759
|
+
session_id=group_id,
|
|
1760
|
+
)
|
|
1761
|
+
except Exception:
|
|
1762
|
+
pass # Don't fail agent run if hook fails
|
|
1763
|
+
|
|
1754
1764
|
# Import shell process status helper
|
|
1755
1765
|
|
|
1756
1766
|
loop = asyncio.get_running_loop()
|
|
@@ -1832,39 +1842,53 @@ class BaseAgent(ABC):
|
|
|
1832
1842
|
except Exception:
|
|
1833
1843
|
pass # Don't fail the run if cache update fails
|
|
1834
1844
|
|
|
1835
|
-
#
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
else:
|
|
1845
|
-
response_text = str(result)
|
|
1846
|
-
|
|
1847
|
-
# Fire the callback - don't await to avoid blocking return
|
|
1848
|
-
# Use asyncio.create_task to run it in background
|
|
1849
|
-
asyncio.create_task(
|
|
1850
|
-
on_agent_response_complete(
|
|
1851
|
-
agent_name=self.name,
|
|
1852
|
-
response_text=response_text,
|
|
1853
|
-
session_id=group_id,
|
|
1854
|
-
metadata={"model": self.get_model_name()},
|
|
1855
|
-
)
|
|
1856
|
-
)
|
|
1857
|
-
except Exception:
|
|
1858
|
-
pass # Don't fail the run if callback fails
|
|
1845
|
+
# Extract response text for the callback
|
|
1846
|
+
_run_response_text = ""
|
|
1847
|
+
if result is not None:
|
|
1848
|
+
if hasattr(result, "data"):
|
|
1849
|
+
_run_response_text = str(result.data) if result.data else ""
|
|
1850
|
+
elif hasattr(result, "output"):
|
|
1851
|
+
_run_response_text = str(result.output) if result.output else ""
|
|
1852
|
+
else:
|
|
1853
|
+
_run_response_text = str(result)
|
|
1859
1854
|
|
|
1855
|
+
_run_success = True
|
|
1856
|
+
_run_error = None
|
|
1860
1857
|
return result
|
|
1861
1858
|
except asyncio.CancelledError:
|
|
1859
|
+
_run_success = False
|
|
1860
|
+
_run_error = None # Cancellation is not an error
|
|
1861
|
+
_run_response_text = ""
|
|
1862
1862
|
agent_task.cancel()
|
|
1863
1863
|
except KeyboardInterrupt:
|
|
1864
|
-
|
|
1864
|
+
_run_success = False
|
|
1865
|
+
_run_error = None # User interrupt is not an error
|
|
1866
|
+
_run_response_text = ""
|
|
1865
1867
|
if not agent_task.done():
|
|
1866
1868
|
agent_task.cancel()
|
|
1869
|
+
except Exception as e:
|
|
1870
|
+
_run_success = False
|
|
1871
|
+
_run_error = e
|
|
1872
|
+
_run_response_text = ""
|
|
1873
|
+
raise
|
|
1867
1874
|
finally:
|
|
1875
|
+
# Fire agent_run_end hook - plugins can use this for:
|
|
1876
|
+
# - Stopping background tasks (token refresh heartbeats)
|
|
1877
|
+
# - Workflow orchestration (Ralph's autonomous loop)
|
|
1878
|
+
# - Logging/analytics
|
|
1879
|
+
try:
|
|
1880
|
+
await on_agent_run_end(
|
|
1881
|
+
agent_name=self.name,
|
|
1882
|
+
model_name=self.get_model_name(),
|
|
1883
|
+
session_id=group_id,
|
|
1884
|
+
success=_run_success,
|
|
1885
|
+
error=_run_error,
|
|
1886
|
+
response_text=_run_response_text,
|
|
1887
|
+
metadata={"model": self.get_model_name()},
|
|
1888
|
+
)
|
|
1889
|
+
except Exception:
|
|
1890
|
+
pass # Don't fail cleanup if hook fails
|
|
1891
|
+
|
|
1868
1892
|
# Stop keyboard listener if it was started
|
|
1869
1893
|
if key_listener_stop_event is not None:
|
|
1870
1894
|
key_listener_stop_event.set()
|
|
@@ -25,7 +25,8 @@ PhaseType = Literal[
|
|
|
25
25
|
"register_agents",
|
|
26
26
|
"register_model_type",
|
|
27
27
|
"get_model_system_prompt",
|
|
28
|
-
"
|
|
28
|
+
"agent_run_start",
|
|
29
|
+
"agent_run_end",
|
|
29
30
|
]
|
|
30
31
|
CallbackFunc = Callable[..., Any]
|
|
31
32
|
|
|
@@ -51,7 +52,8 @@ _callbacks: Dict[PhaseType, List[CallbackFunc]] = {
|
|
|
51
52
|
"register_agents": [],
|
|
52
53
|
"register_model_type": [],
|
|
53
54
|
"get_model_system_prompt": [],
|
|
54
|
-
"
|
|
55
|
+
"agent_run_start": [],
|
|
56
|
+
"agent_run_end": [],
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
logger = logging.getLogger(__name__)
|
|
@@ -446,26 +448,72 @@ def on_get_model_system_prompt(
|
|
|
446
448
|
)
|
|
447
449
|
|
|
448
450
|
|
|
449
|
-
async def
|
|
451
|
+
async def on_agent_run_start(
|
|
450
452
|
agent_name: str,
|
|
451
|
-
|
|
453
|
+
model_name: str,
|
|
452
454
|
session_id: str | None = None,
|
|
455
|
+
) -> List[Any]:
|
|
456
|
+
"""Trigger callbacks when an agent run starts.
|
|
457
|
+
|
|
458
|
+
This fires at the beginning of run_with_mcp, before the agent task is created.
|
|
459
|
+
Useful for:
|
|
460
|
+
- Starting background tasks (like token refresh heartbeats)
|
|
461
|
+
- Logging/analytics
|
|
462
|
+
- Resource allocation
|
|
463
|
+
|
|
464
|
+
Args:
|
|
465
|
+
agent_name: Name of the agent starting
|
|
466
|
+
model_name: Name of the model being used
|
|
467
|
+
session_id: Optional session identifier
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
List of results from registered callbacks.
|
|
471
|
+
"""
|
|
472
|
+
return await _trigger_callbacks(
|
|
473
|
+
"agent_run_start", agent_name, model_name, session_id
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
async def on_agent_run_end(
|
|
478
|
+
agent_name: str,
|
|
479
|
+
model_name: str,
|
|
480
|
+
session_id: str | None = None,
|
|
481
|
+
success: bool = True,
|
|
482
|
+
error: Exception | None = None,
|
|
483
|
+
response_text: str | None = None,
|
|
453
484
|
metadata: dict | None = None,
|
|
454
485
|
) -> List[Any]:
|
|
455
|
-
"""Trigger callbacks
|
|
486
|
+
"""Trigger callbacks when an agent run ends.
|
|
487
|
+
|
|
488
|
+
This fires at the end of run_with_mcp, in the finally block.
|
|
489
|
+
Always fires regardless of success/failure/cancellation.
|
|
456
490
|
|
|
457
|
-
This fires after all tool calls are resolved and the agent has finished.
|
|
458
491
|
Useful for:
|
|
492
|
+
- Stopping background tasks (like token refresh heartbeats)
|
|
459
493
|
- Workflow orchestration (like Ralph's autonomous loop)
|
|
460
494
|
- Logging/analytics
|
|
495
|
+
- Resource cleanup
|
|
461
496
|
- Detecting completion signals in responses
|
|
462
497
|
|
|
463
498
|
Args:
|
|
464
|
-
agent_name: Name of the agent that
|
|
465
|
-
|
|
499
|
+
agent_name: Name of the agent that finished
|
|
500
|
+
model_name: Name of the model that was used
|
|
466
501
|
session_id: Optional session identifier
|
|
502
|
+
success: Whether the run completed successfully
|
|
503
|
+
error: Exception if the run failed, None otherwise
|
|
504
|
+
response_text: The final text response from the agent (if successful)
|
|
467
505
|
metadata: Optional dict with additional context (tokens used, etc.)
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
List of results from registered callbacks.
|
|
468
509
|
"""
|
|
469
510
|
return await _trigger_callbacks(
|
|
470
|
-
"
|
|
511
|
+
"agent_run_end",
|
|
512
|
+
agent_name,
|
|
513
|
+
model_name,
|
|
514
|
+
session_id,
|
|
515
|
+
success,
|
|
516
|
+
error,
|
|
517
|
+
response_text,
|
|
518
|
+
metadata,
|
|
471
519
|
)
|
|
@@ -106,6 +106,19 @@ SETTING_DEFINITIONS: Dict[str, Dict] = {
|
|
|
106
106
|
"type": "boolean",
|
|
107
107
|
"default": False,
|
|
108
108
|
},
|
|
109
|
+
"thinking_enabled": {
|
|
110
|
+
"name": "Thinking Enabled",
|
|
111
|
+
"description": "Enable thinking mode for Gemini 3 Pro models. When enabled, the model will show its reasoning process.",
|
|
112
|
+
"type": "boolean",
|
|
113
|
+
"default": True,
|
|
114
|
+
},
|
|
115
|
+
"thinking_level": {
|
|
116
|
+
"name": "Thinking Level",
|
|
117
|
+
"description": "Controls the depth of thinking for Gemini 3 Pro models. Low = faster responses, High = more thorough reasoning.",
|
|
118
|
+
"type": "choice",
|
|
119
|
+
"choices": ["low", "high"],
|
|
120
|
+
"default": "low",
|
|
121
|
+
},
|
|
109
122
|
}
|
|
110
123
|
|
|
111
124
|
|
|
@@ -40,6 +40,10 @@ from pydantic_ai.usage import RequestUsage
|
|
|
40
40
|
|
|
41
41
|
logger = logging.getLogger(__name__)
|
|
42
42
|
|
|
43
|
+
# Bypass thought signature for Gemini when no pending signature is available
|
|
44
|
+
# This allows function calls to work with thinking models
|
|
45
|
+
BYPASS_THOUGHT_SIGNATURE = "context_engineering_is_the_way_to_go"
|
|
46
|
+
|
|
43
47
|
|
|
44
48
|
def generate_tool_call_id() -> str:
|
|
45
49
|
"""Generate a unique tool call ID."""
|
|
@@ -410,27 +414,48 @@ class GeminiModel(Model):
|
|
|
410
414
|
return system_instruction, contents
|
|
411
415
|
|
|
412
416
|
def _map_model_response(self, m: ModelResponse) -> dict[str, Any] | None:
|
|
413
|
-
"""Map a ModelResponse to Gemini content format.
|
|
417
|
+
"""Map a ModelResponse to Gemini content format.
|
|
418
|
+
|
|
419
|
+
For Gemini thinking models, we need to track thought signatures from
|
|
420
|
+
ThinkingParts and apply them to subsequent function_call parts.
|
|
421
|
+
"""
|
|
414
422
|
parts: list[dict[str, Any]] = []
|
|
423
|
+
pending_signature: str | None = None
|
|
415
424
|
|
|
416
425
|
for item in m.parts:
|
|
417
426
|
if isinstance(item, ToolCallPart):
|
|
418
|
-
|
|
419
|
-
{
|
|
420
|
-
"
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
"id": item.tool_call_id,
|
|
424
|
-
}
|
|
427
|
+
part_dict: dict[str, Any] = {
|
|
428
|
+
"function_call": {
|
|
429
|
+
"name": item.tool_name,
|
|
430
|
+
"args": item.args_as_dict(),
|
|
431
|
+
"id": item.tool_call_id,
|
|
425
432
|
}
|
|
433
|
+
}
|
|
434
|
+
# Gemini thinking models REQUIRE thoughtSignature on function calls
|
|
435
|
+
# Use pending signature from thinking or bypass signature
|
|
436
|
+
part_dict["thoughtSignature"] = (
|
|
437
|
+
pending_signature
|
|
438
|
+
if pending_signature is not None
|
|
439
|
+
else BYPASS_THOUGHT_SIGNATURE
|
|
426
440
|
)
|
|
441
|
+
parts.append(part_dict)
|
|
427
442
|
elif isinstance(item, TextPart):
|
|
428
|
-
|
|
443
|
+
part_dict = {"text": item.content}
|
|
444
|
+
# Apply pending signature to text parts too if present
|
|
445
|
+
if pending_signature is not None:
|
|
446
|
+
part_dict["thoughtSignature"] = pending_signature
|
|
447
|
+
pending_signature = None
|
|
448
|
+
parts.append(part_dict)
|
|
429
449
|
elif isinstance(item, ThinkingPart):
|
|
430
450
|
if item.content:
|
|
431
|
-
part_dict
|
|
451
|
+
part_dict = {"text": item.content, "thought": True}
|
|
432
452
|
if item.signature:
|
|
433
453
|
part_dict["thoughtSignature"] = item.signature
|
|
454
|
+
# Store signature for subsequent parts
|
|
455
|
+
pending_signature = item.signature
|
|
456
|
+
else:
|
|
457
|
+
# No signature on thinking part, use bypass
|
|
458
|
+
pending_signature = BYPASS_THOUGHT_SIGNATURE
|
|
434
459
|
parts.append(part_dict)
|
|
435
460
|
|
|
436
461
|
if not parts:
|
|
@@ -462,18 +487,34 @@ class GeminiModel(Model):
|
|
|
462
487
|
config: dict[str, Any] = {}
|
|
463
488
|
|
|
464
489
|
if model_settings:
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
config["maxOutputTokens"] =
|
|
490
|
+
# ModelSettings is a TypedDict, so use .get() for all access
|
|
491
|
+
temperature = model_settings.get("temperature")
|
|
492
|
+
if temperature is not None:
|
|
493
|
+
config["temperature"] = temperature
|
|
494
|
+
|
|
495
|
+
top_p = model_settings.get("top_p")
|
|
496
|
+
if top_p is not None:
|
|
497
|
+
config["topP"] = top_p
|
|
498
|
+
|
|
499
|
+
max_tokens = model_settings.get("max_tokens")
|
|
500
|
+
if max_tokens is not None:
|
|
501
|
+
config["maxOutputTokens"] = max_tokens
|
|
502
|
+
|
|
503
|
+
# Handle Gemini 3 Pro thinking settings
|
|
504
|
+
thinking_enabled = model_settings.get("thinking_enabled")
|
|
505
|
+
thinking_level = model_settings.get("thinking_level")
|
|
506
|
+
|
|
507
|
+
# Build thinkingConfig if thinking settings are present
|
|
508
|
+
if thinking_enabled is False:
|
|
509
|
+
# Disable thinking by not including thinkingConfig
|
|
510
|
+
pass
|
|
511
|
+
elif thinking_level is not None:
|
|
512
|
+
# Gemini 3 Pro uses thinkingLevel with values "low" or "high"
|
|
513
|
+
# includeThoughts=True is required to surface the thinking in the response
|
|
514
|
+
config["thinkingConfig"] = {
|
|
515
|
+
"thinkingLevel": thinking_level,
|
|
516
|
+
"includeThoughts": True,
|
|
517
|
+
}
|
|
477
518
|
|
|
478
519
|
return config
|
|
479
520
|
|
|
@@ -74,6 +74,7 @@ def make_model_settings(
|
|
|
74
74
|
get_effective_model_settings,
|
|
75
75
|
get_openai_reasoning_effort,
|
|
76
76
|
get_openai_verbosity,
|
|
77
|
+
model_supports_setting,
|
|
77
78
|
)
|
|
78
79
|
|
|
79
80
|
model_settings_dict: dict = {}
|
|
@@ -131,6 +132,18 @@ def make_model_settings(
|
|
|
131
132
|
}
|
|
132
133
|
model_settings = AnthropicModelSettings(**model_settings_dict)
|
|
133
134
|
|
|
135
|
+
# Handle Gemini thinking models (Gemini-3)
|
|
136
|
+
# Check if model supports thinking settings and apply defaults
|
|
137
|
+
if model_supports_setting(model_name, "thinking_level"):
|
|
138
|
+
# Apply defaults if not explicitly set by user
|
|
139
|
+
# Default: thinking_enabled=True, thinking_level="low"
|
|
140
|
+
if "thinking_enabled" not in model_settings_dict:
|
|
141
|
+
model_settings_dict["thinking_enabled"] = True
|
|
142
|
+
if "thinking_level" not in model_settings_dict:
|
|
143
|
+
model_settings_dict["thinking_level"] = "low"
|
|
144
|
+
# Recreate settings with Gemini thinking config
|
|
145
|
+
model_settings = ModelSettings(**model_settings_dict)
|
|
146
|
+
|
|
134
147
|
return model_settings
|
|
135
148
|
|
|
136
149
|
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"type": "gemini",
|
|
34
34
|
"name": "gemini-3-pro-preview",
|
|
35
35
|
"context_length": 200000,
|
|
36
|
-
"supported_settings": ["temperature", "top_p"]
|
|
36
|
+
"supported_settings": ["temperature", "top_p", "thinking_enabled", "thinking_level"]
|
|
37
37
|
},
|
|
38
38
|
"Gemini-3-Long-Context": {
|
|
39
39
|
"type": "gemini",
|
|
40
40
|
"name": "gemini-3-pro-preview",
|
|
41
41
|
"context_length": 1000000,
|
|
42
|
-
"supported_settings": ["temperature", "top_p"]
|
|
42
|
+
"supported_settings": ["temperature", "top_p", "thinking_enabled", "thinking_level"]
|
|
43
43
|
},
|
|
44
44
|
"gpt-5.1": {
|
|
45
45
|
"type": "openai",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Claude Code OAuth Plugin for Code Puppy
|
|
3
|
+
|
|
4
|
+
This plugin provides OAuth authentication for Claude Code and automatically
|
|
5
|
+
adds available models to the extra_models.json configuration.
|
|
6
|
+
|
|
7
|
+
The plugin also includes a token refresh heartbeat for maintaining fresh
|
|
8
|
+
tokens during long-running agentic operations.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .token_refresh_heartbeat import (
|
|
12
|
+
TokenRefreshHeartbeat,
|
|
13
|
+
force_token_refresh,
|
|
14
|
+
get_current_heartbeat,
|
|
15
|
+
is_heartbeat_running,
|
|
16
|
+
token_refresh_heartbeat_context,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"TokenRefreshHeartbeat",
|
|
21
|
+
"token_refresh_heartbeat_context",
|
|
22
|
+
"is_heartbeat_running",
|
|
23
|
+
"get_current_heartbeat",
|
|
24
|
+
"force_token_refresh",
|
|
25
|
+
]
|
{code_puppy-0.0.375 → code_puppy-0.0.377}/code_puppy/plugins/claude_code_oauth/register_callbacks.py
RENAMED
|
@@ -363,6 +363,78 @@ def _register_model_types() -> List[Dict[str, Any]]:
|
|
|
363
363
|
return [{"type": "claude_code", "handler": _create_claude_code_model}]
|
|
364
364
|
|
|
365
365
|
|
|
366
|
+
# Global storage for the token refresh heartbeat
|
|
367
|
+
# Using a dict to allow multiple concurrent agent runs (keyed by session_id)
|
|
368
|
+
_active_heartbeats: Dict[str, Any] = {}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
async def _on_agent_run_start(
|
|
372
|
+
agent_name: str,
|
|
373
|
+
model_name: str,
|
|
374
|
+
session_id: Optional[str] = None,
|
|
375
|
+
) -> None:
|
|
376
|
+
"""Start token refresh heartbeat for Claude Code OAuth models.
|
|
377
|
+
|
|
378
|
+
This callback is triggered when an agent run starts. If the model is a
|
|
379
|
+
Claude Code OAuth model, we start a background heartbeat to keep the
|
|
380
|
+
token fresh during long-running operations.
|
|
381
|
+
"""
|
|
382
|
+
# Only start heartbeat for Claude Code models
|
|
383
|
+
if not model_name.startswith("claude-code"):
|
|
384
|
+
return
|
|
385
|
+
|
|
386
|
+
try:
|
|
387
|
+
from .token_refresh_heartbeat import TokenRefreshHeartbeat
|
|
388
|
+
|
|
389
|
+
heartbeat = TokenRefreshHeartbeat()
|
|
390
|
+
await heartbeat.start()
|
|
391
|
+
|
|
392
|
+
# Store heartbeat for cleanup, keyed by session_id
|
|
393
|
+
key = session_id or "default"
|
|
394
|
+
_active_heartbeats[key] = heartbeat
|
|
395
|
+
logger.debug(
|
|
396
|
+
"Started token refresh heartbeat for session %s (model: %s)",
|
|
397
|
+
key,
|
|
398
|
+
model_name,
|
|
399
|
+
)
|
|
400
|
+
except ImportError:
|
|
401
|
+
logger.debug("Token refresh heartbeat module not available")
|
|
402
|
+
except Exception as exc:
|
|
403
|
+
logger.debug("Failed to start token refresh heartbeat: %s", exc)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
async def _on_agent_run_end(
|
|
407
|
+
agent_name: str,
|
|
408
|
+
model_name: str,
|
|
409
|
+
session_id: Optional[str] = None,
|
|
410
|
+
success: bool = True,
|
|
411
|
+
error: Optional[Exception] = None,
|
|
412
|
+
response_text: Optional[str] = None,
|
|
413
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
414
|
+
) -> None:
|
|
415
|
+
"""Stop token refresh heartbeat when agent run ends.
|
|
416
|
+
|
|
417
|
+
This callback is triggered when an agent run completes (success or failure).
|
|
418
|
+
We stop any heartbeat that was started for this session.
|
|
419
|
+
"""
|
|
420
|
+
# We don't use response_text or metadata, just cleanup the heartbeat
|
|
421
|
+
key = session_id or "default"
|
|
422
|
+
heartbeat = _active_heartbeats.pop(key, None)
|
|
423
|
+
|
|
424
|
+
if heartbeat is not None:
|
|
425
|
+
try:
|
|
426
|
+
await heartbeat.stop()
|
|
427
|
+
logger.debug(
|
|
428
|
+
"Stopped token refresh heartbeat for session %s (refreshed %d times)",
|
|
429
|
+
key,
|
|
430
|
+
heartbeat.refresh_count,
|
|
431
|
+
)
|
|
432
|
+
except Exception as exc:
|
|
433
|
+
logger.debug("Error stopping token refresh heartbeat: %s", exc)
|
|
434
|
+
|
|
435
|
+
|
|
366
436
|
register_callback("custom_command_help", _custom_help)
|
|
367
437
|
register_callback("custom_command", _handle_custom_command)
|
|
368
438
|
register_callback("register_model_type", _register_model_types)
|
|
439
|
+
register_callback("agent_run_start", _on_agent_run_start)
|
|
440
|
+
register_callback("agent_run_end", _on_agent_run_end)
|