code-puppy 0.0.366__tar.gz → 0.0.368__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.366 → code_puppy-0.0.368}/.gitignore +2 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/PKG-INFO +2 -2
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/claude_cache_client.py +45 -7
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/gemini_model.py +115 -11
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +5 -7
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/transport.py +131 -43
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/claude_code_oauth/utils.py +4 -1
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/pydantic_patches.py +62 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/pyproject.toml +3 -4
- {code_puppy-0.0.366 → code_puppy-0.0.368}/LICENSE +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/README.md +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_pack_leader.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_python_programmer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_terminal_qa.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/pack/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/pack/bloodhound.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/pack/husky.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/pack/retriever.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/pack/shepherd.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/pack/terrier.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/pack/watchdog.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/prompt_reviewer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/app.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/main.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/pty_manager.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/routers/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/routers/agents.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/routers/commands.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/routers/config.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/routers/sessions.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/templates/terminal.html +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/api/websocket.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/cli_runner.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/config.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/main.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/messaging/subagent_console.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/models.json +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/prompts/antigravity_system_prompt.md +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/prompts/codex_system_prompt.md +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_manager.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/chromium_terminal_manager.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/terminal_command_tools.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/terminal_screenshot_tools.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/browser/terminal_tools.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/uvx_detection.py +0 -0
- {code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/version_checker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-puppy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.368
|
|
4
4
|
Summary: Code generation agent
|
|
5
5
|
Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
|
|
6
6
|
Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
|
|
@@ -24,7 +24,7 @@ Requires-Dist: openai>=1.99.1
|
|
|
24
24
|
Requires-Dist: pillow>=10.0.0
|
|
25
25
|
Requires-Dist: playwright>=1.40.0
|
|
26
26
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
27
|
-
Requires-Dist: pydantic-ai-slim[anthropic,openai]==1.
|
|
27
|
+
Requires-Dist: pydantic-ai-slim[anthropic,openai]==1.26.0
|
|
28
28
|
Requires-Dist: pydantic>=2.4.0
|
|
29
29
|
Requires-Dist: pyfiglet>=0.8.post1
|
|
30
30
|
Requires-Dist: python-dotenv>=1.0.0
|
|
@@ -119,24 +119,62 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
|
|
|
119
119
|
return None
|
|
120
120
|
|
|
121
121
|
def _should_refresh_token(self, request: httpx.Request) -> bool:
|
|
122
|
-
"""Check if the token
|
|
122
|
+
"""Check if the token should be refreshed (within 1 hour of expiry).
|
|
123
|
+
|
|
124
|
+
Uses two strategies:
|
|
125
|
+
1. Decode JWT to check token age (if possible)
|
|
126
|
+
2. Fall back to stored expires_at from token file
|
|
127
|
+
|
|
128
|
+
Returns True if token expires within TOKEN_MAX_AGE_SECONDS (1 hour).
|
|
129
|
+
"""
|
|
123
130
|
token = self._extract_bearer_token(request)
|
|
124
131
|
if not token:
|
|
125
132
|
return False
|
|
126
133
|
|
|
134
|
+
# Strategy 1: Try to decode JWT age
|
|
127
135
|
age = self._get_jwt_age_seconds(token)
|
|
128
|
-
if age is None:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
136
|
+
if age is not None:
|
|
137
|
+
should_refresh = age >= TOKEN_MAX_AGE_SECONDS
|
|
138
|
+
if should_refresh:
|
|
139
|
+
logger.info(
|
|
140
|
+
"JWT token is %.1f seconds old (>= %d), will refresh proactively",
|
|
141
|
+
age,
|
|
142
|
+
TOKEN_MAX_AGE_SECONDS,
|
|
143
|
+
)
|
|
144
|
+
return should_refresh
|
|
145
|
+
|
|
146
|
+
# Strategy 2: Fall back to stored expires_at from token file
|
|
147
|
+
should_refresh = self._check_stored_token_expiry()
|
|
132
148
|
if should_refresh:
|
|
133
149
|
logger.info(
|
|
134
|
-
"
|
|
135
|
-
age,
|
|
150
|
+
"Stored token expires within %d seconds, will refresh proactively",
|
|
136
151
|
TOKEN_MAX_AGE_SECONDS,
|
|
137
152
|
)
|
|
138
153
|
return should_refresh
|
|
139
154
|
|
|
155
|
+
@staticmethod
|
|
156
|
+
def _check_stored_token_expiry() -> bool:
|
|
157
|
+
"""Check if the stored token expires within TOKEN_MAX_AGE_SECONDS.
|
|
158
|
+
|
|
159
|
+
This is a fallback for when JWT decoding fails or isn't available.
|
|
160
|
+
Uses the expires_at timestamp from the stored token file.
|
|
161
|
+
"""
|
|
162
|
+
try:
|
|
163
|
+
from code_puppy.plugins.claude_code_oauth.utils import (
|
|
164
|
+
is_token_expired,
|
|
165
|
+
load_stored_tokens,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
tokens = load_stored_tokens()
|
|
169
|
+
if not tokens:
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
# is_token_expired already uses TOKEN_REFRESH_BUFFER_SECONDS (1 hour)
|
|
173
|
+
return is_token_expired(tokens)
|
|
174
|
+
except Exception as exc:
|
|
175
|
+
logger.debug("Error checking stored token expiry: %s", exc)
|
|
176
|
+
return False
|
|
177
|
+
|
|
140
178
|
@staticmethod
|
|
141
179
|
def _prefix_tool_names(body: bytes) -> bytes | None:
|
|
142
180
|
"""Prefix all tool names in the request body with TOOL_PREFIX.
|
|
@@ -46,6 +46,58 @@ def generate_tool_call_id() -> str:
|
|
|
46
46
|
return str(uuid.uuid4())
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
def _flatten_union_to_object_gemini(union_items: list, defs: dict, resolve_fn) -> dict:
|
|
50
|
+
"""Flatten a union of object types into a single object with all properties.
|
|
51
|
+
|
|
52
|
+
For discriminated unions like EditFilePayload, we merge all object types
|
|
53
|
+
into one with all properties (Gemini doesn't support anyOf/oneOf).
|
|
54
|
+
"""
|
|
55
|
+
import copy as copy_module
|
|
56
|
+
|
|
57
|
+
merged_properties = {}
|
|
58
|
+
has_string_type = False
|
|
59
|
+
|
|
60
|
+
for item in union_items:
|
|
61
|
+
if not isinstance(item, dict):
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
# Resolve $ref first
|
|
65
|
+
if "$ref" in item:
|
|
66
|
+
ref_path = item["$ref"]
|
|
67
|
+
ref_name = None
|
|
68
|
+
if ref_path.startswith("#/$defs/"):
|
|
69
|
+
ref_name = ref_path[8:]
|
|
70
|
+
elif ref_path.startswith("#/definitions/"):
|
|
71
|
+
ref_name = ref_path[14:]
|
|
72
|
+
if ref_name and ref_name in defs:
|
|
73
|
+
item = copy_module.deepcopy(defs[ref_name])
|
|
74
|
+
else:
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
if item.get("type") == "string":
|
|
78
|
+
has_string_type = True
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
if item.get("type") == "null":
|
|
82
|
+
continue
|
|
83
|
+
|
|
84
|
+
if item.get("type") == "object" or "properties" in item:
|
|
85
|
+
props = item.get("properties", {})
|
|
86
|
+
for prop_name, prop_schema in props.items():
|
|
87
|
+
if prop_name not in merged_properties:
|
|
88
|
+
merged_properties[prop_name] = resolve_fn(
|
|
89
|
+
copy_module.deepcopy(prop_schema)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if not merged_properties:
|
|
93
|
+
return {"type": "string"} if has_string_type else {"type": "object"}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"properties": merged_properties,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
49
101
|
def _sanitize_schema_for_gemini(schema: dict) -> dict:
|
|
50
102
|
"""Sanitize JSON schema for Gemini API compatibility.
|
|
51
103
|
|
|
@@ -53,7 +105,9 @@ def _sanitize_schema_for_gemini(schema: dict) -> dict:
|
|
|
53
105
|
- $defs, definitions, $schema, $id
|
|
54
106
|
- additionalProperties
|
|
55
107
|
- $ref (inlined)
|
|
56
|
-
- anyOf/oneOf/allOf (
|
|
108
|
+
- anyOf/oneOf/allOf (flattened - Gemini doesn't support unions!)
|
|
109
|
+
- For unions of objects: merges into single object with all properties
|
|
110
|
+
- For simple unions (string | null): picks first non-null type
|
|
57
111
|
"""
|
|
58
112
|
import copy
|
|
59
113
|
|
|
@@ -69,6 +123,62 @@ def _sanitize_schema_for_gemini(schema: dict) -> dict:
|
|
|
69
123
|
def resolve_refs(obj):
|
|
70
124
|
"""Recursively resolve $ref references and clean schema."""
|
|
71
125
|
if isinstance(obj, dict):
|
|
126
|
+
# Handle anyOf/oneOf unions
|
|
127
|
+
for union_key in ["anyOf", "oneOf"]:
|
|
128
|
+
if union_key in obj:
|
|
129
|
+
union = obj[union_key]
|
|
130
|
+
if isinstance(union, list):
|
|
131
|
+
# Check if this is a complex union of objects
|
|
132
|
+
object_count = 0
|
|
133
|
+
has_refs = False
|
|
134
|
+
for item in union:
|
|
135
|
+
if isinstance(item, dict):
|
|
136
|
+
if "$ref" in item:
|
|
137
|
+
has_refs = True
|
|
138
|
+
object_count += 1
|
|
139
|
+
elif (
|
|
140
|
+
item.get("type") == "object" or "properties" in item
|
|
141
|
+
):
|
|
142
|
+
object_count += 1
|
|
143
|
+
|
|
144
|
+
# If multiple objects or has refs, flatten to single object
|
|
145
|
+
if object_count > 1 or has_refs:
|
|
146
|
+
flattened = _flatten_union_to_object_gemini(
|
|
147
|
+
union, defs, resolve_refs
|
|
148
|
+
)
|
|
149
|
+
if "description" in obj:
|
|
150
|
+
flattened["description"] = obj["description"]
|
|
151
|
+
return flattened
|
|
152
|
+
|
|
153
|
+
# Simple union - pick first non-null type
|
|
154
|
+
for item in union:
|
|
155
|
+
if isinstance(item, dict) and item.get("type") != "null":
|
|
156
|
+
result = dict(item)
|
|
157
|
+
if "description" in obj:
|
|
158
|
+
result["description"] = obj["description"]
|
|
159
|
+
return resolve_refs(result)
|
|
160
|
+
|
|
161
|
+
# Handle allOf by merging all schemas
|
|
162
|
+
if "allOf" in obj:
|
|
163
|
+
all_of = obj["allOf"]
|
|
164
|
+
if isinstance(all_of, list):
|
|
165
|
+
merged = {}
|
|
166
|
+
merged_properties = {}
|
|
167
|
+
for item in all_of:
|
|
168
|
+
if isinstance(item, dict):
|
|
169
|
+
resolved_item = resolve_refs(item)
|
|
170
|
+
if "properties" in resolved_item:
|
|
171
|
+
merged_properties.update(
|
|
172
|
+
resolved_item.pop("properties")
|
|
173
|
+
)
|
|
174
|
+
merged.update(resolved_item)
|
|
175
|
+
if merged_properties:
|
|
176
|
+
merged["properties"] = merged_properties
|
|
177
|
+
for k, v in obj.items():
|
|
178
|
+
if k != "allOf":
|
|
179
|
+
merged[k] = v
|
|
180
|
+
return resolve_refs(merged)
|
|
181
|
+
|
|
72
182
|
# Check for $ref
|
|
73
183
|
if "$ref" in obj:
|
|
74
184
|
ref_path = obj["$ref"]
|
|
@@ -102,19 +212,13 @@ def _sanitize_schema_for_gemini(schema: dict) -> dict:
|
|
|
102
212
|
"default",
|
|
103
213
|
"examples",
|
|
104
214
|
"const",
|
|
215
|
+
"anyOf", # Skip any remaining union types
|
|
216
|
+
"oneOf",
|
|
217
|
+
"allOf",
|
|
105
218
|
):
|
|
106
219
|
continue
|
|
107
220
|
|
|
108
|
-
|
|
109
|
-
new_key = key
|
|
110
|
-
if key == "anyOf":
|
|
111
|
-
new_key = "any_of"
|
|
112
|
-
elif key == "oneOf":
|
|
113
|
-
new_key = "one_of"
|
|
114
|
-
elif key == "allOf":
|
|
115
|
-
new_key = "all_of"
|
|
116
|
-
|
|
117
|
-
result[new_key] = resolve_refs(value)
|
|
221
|
+
result[key] = resolve_refs(value)
|
|
118
222
|
return result
|
|
119
223
|
elif isinstance(obj, list):
|
|
120
224
|
return [resolve_refs(item) for item in obj]
|
{code_puppy-0.0.366 → code_puppy-0.0.368}/code_puppy/plugins/antigravity_oauth/antigravity_model.py
RENAMED
|
@@ -99,12 +99,11 @@ class AntigravityModel(GeminiModel):
|
|
|
99
99
|
def _build_tools(self, tools: list) -> list[dict]:
|
|
100
100
|
"""Build tool definitions with model-appropriate schema handling.
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
102
|
+
Both Gemini and Claude require simplified union types in function schemas:
|
|
103
|
+
- Neither supports anyOf/oneOf/allOf in function parameter schemas
|
|
104
|
+
- We simplify by picking the first non-null type from unions
|
|
105
105
|
"""
|
|
106
106
|
|
|
107
|
-
is_claude = self._is_claude_model()
|
|
108
107
|
function_declarations = []
|
|
109
108
|
|
|
110
109
|
for tool in tools:
|
|
@@ -113,11 +112,10 @@ class AntigravityModel(GeminiModel):
|
|
|
113
112
|
"description": tool.description or "",
|
|
114
113
|
}
|
|
115
114
|
if tool.parameters_json_schema:
|
|
116
|
-
#
|
|
115
|
+
# Simplify union types for all models (Gemini and Claude both need this)
|
|
117
116
|
func_decl["parameters"] = _inline_refs(
|
|
118
117
|
tool.parameters_json_schema,
|
|
119
|
-
|
|
120
|
-
simplify_for_claude=is_claude, # Claude needs simplified unions
|
|
118
|
+
simplify_unions=True, # Both Gemini and Claude need simplified unions
|
|
121
119
|
)
|
|
122
120
|
function_declarations.append(func_decl)
|
|
123
121
|
|
|
@@ -23,20 +23,78 @@ from .constants import (
|
|
|
23
23
|
logger = logging.getLogger(__name__)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
def _flatten_union_to_object(union_items: list, defs: dict, resolve_fn) -> dict:
|
|
27
|
+
"""Flatten a union of object types into a single object with all properties.
|
|
28
|
+
|
|
29
|
+
For discriminated unions like EditFilePayload (ContentPayload | ReplacementsPayload | DeleteSnippetPayload),
|
|
30
|
+
we merge all object types into one with all properties marked as optional.
|
|
31
|
+
"""
|
|
32
|
+
merged_properties = {}
|
|
33
|
+
has_string_type = False
|
|
34
|
+
|
|
35
|
+
for item in union_items:
|
|
36
|
+
if not isinstance(item, dict):
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
# Resolve $ref first
|
|
40
|
+
if "$ref" in item:
|
|
41
|
+
ref_path = item["$ref"]
|
|
42
|
+
ref_name = None
|
|
43
|
+
if ref_path.startswith("#/$defs/"):
|
|
44
|
+
ref_name = ref_path[8:]
|
|
45
|
+
elif ref_path.startswith("#/definitions/"):
|
|
46
|
+
ref_name = ref_path[14:]
|
|
47
|
+
if ref_name and ref_name in defs:
|
|
48
|
+
item = copy.deepcopy(defs[ref_name])
|
|
49
|
+
else:
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
# Check for string type (common fallback)
|
|
53
|
+
if item.get("type") == "string":
|
|
54
|
+
has_string_type = True
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
# Skip null types
|
|
58
|
+
if item.get("type") == "null":
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
# Merge properties from object types
|
|
62
|
+
if item.get("type") == "object" or "properties" in item:
|
|
63
|
+
props = item.get("properties", {})
|
|
64
|
+
for prop_name, prop_schema in props.items():
|
|
65
|
+
if prop_name not in merged_properties:
|
|
66
|
+
# Resolve the property schema
|
|
67
|
+
merged_properties[prop_name] = resolve_fn(
|
|
68
|
+
copy.deepcopy(prop_schema)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if not merged_properties:
|
|
72
|
+
# No object properties found, return string type as fallback
|
|
73
|
+
return {"type": "string"} if has_string_type else {"type": "object"}
|
|
74
|
+
|
|
75
|
+
# Build merged object - no required fields since any subset is valid
|
|
76
|
+
result = {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"properties": merged_properties,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _inline_refs(schema: dict, simplify_unions: bool = False) -> dict:
|
|
29
85
|
"""Inline $ref references and transform schema for Antigravity compatibility.
|
|
30
86
|
|
|
31
87
|
- Inlines $ref references
|
|
32
88
|
- Removes $defs, definitions, $schema, $id
|
|
33
|
-
- Optionally converts anyOf/oneOf/allOf to any_of/one_of/all_of (only for Gemini)
|
|
34
89
|
- Removes unsupported fields like 'default', 'examples', 'const'
|
|
35
|
-
-
|
|
90
|
+
- When simplify_unions=True: flattens anyOf/oneOf unions:
|
|
91
|
+
- For unions of objects: merges into single object with all properties
|
|
92
|
+
- For simple unions (string | null): picks first non-null type
|
|
93
|
+
(required for both Gemini AND Claude - neither supports union types in function schemas!)
|
|
36
94
|
|
|
37
95
|
Args:
|
|
38
|
-
|
|
39
|
-
|
|
96
|
+
simplify_unions: If True, simplify anyOf/oneOf unions.
|
|
97
|
+
Required for Gemini and Claude models.
|
|
40
98
|
"""
|
|
41
99
|
if not isinstance(schema, dict):
|
|
42
100
|
return schema
|
|
@@ -47,31 +105,73 @@ def _inline_refs(
|
|
|
47
105
|
# Extract $defs for reference resolution
|
|
48
106
|
defs = schema.pop("$defs", schema.pop("definitions", {}))
|
|
49
107
|
|
|
50
|
-
def resolve_refs(
|
|
51
|
-
obj, convert_unions=convert_unions, simplify_for_claude=simplify_for_claude
|
|
52
|
-
):
|
|
108
|
+
def resolve_refs(obj, simplify_unions=simplify_unions):
|
|
53
109
|
"""Recursively resolve $ref references and transform schema."""
|
|
54
110
|
if isinstance(obj, dict):
|
|
55
|
-
#
|
|
56
|
-
if
|
|
111
|
+
# Handle anyOf/oneOf unions
|
|
112
|
+
if simplify_unions:
|
|
57
113
|
for union_key in ["anyOf", "oneOf"]:
|
|
58
114
|
if union_key in obj:
|
|
59
115
|
union = obj[union_key]
|
|
60
116
|
if isinstance(union, list):
|
|
61
|
-
#
|
|
117
|
+
# Check if this is a complex union of objects (discriminated union)
|
|
118
|
+
# vs a simple nullable type (string | null)
|
|
119
|
+
object_count = 0
|
|
120
|
+
has_refs = False
|
|
121
|
+
for item in union:
|
|
122
|
+
if isinstance(item, dict):
|
|
123
|
+
if "$ref" in item:
|
|
124
|
+
has_refs = True
|
|
125
|
+
object_count += 1
|
|
126
|
+
elif (
|
|
127
|
+
item.get("type") == "object"
|
|
128
|
+
or "properties" in item
|
|
129
|
+
):
|
|
130
|
+
object_count += 1
|
|
131
|
+
|
|
132
|
+
# If multiple objects or has refs, flatten to single object
|
|
133
|
+
if object_count > 1 or has_refs:
|
|
134
|
+
flattened = _flatten_union_to_object(
|
|
135
|
+
union, defs, resolve_refs
|
|
136
|
+
)
|
|
137
|
+
# Keep description if present
|
|
138
|
+
if "description" in obj:
|
|
139
|
+
flattened["description"] = obj["description"]
|
|
140
|
+
return flattened
|
|
141
|
+
|
|
142
|
+
# Simple union - pick first non-null type
|
|
62
143
|
for item in union:
|
|
63
144
|
if (
|
|
64
145
|
isinstance(item, dict)
|
|
65
146
|
and item.get("type") != "null"
|
|
66
147
|
):
|
|
67
|
-
# Replace the whole object with this type
|
|
68
148
|
result = dict(item)
|
|
69
|
-
# Keep description if present
|
|
70
149
|
if "description" in obj:
|
|
71
150
|
result["description"] = obj["description"]
|
|
72
|
-
return resolve_refs(
|
|
73
|
-
|
|
74
|
-
|
|
151
|
+
return resolve_refs(result, simplify_unions)
|
|
152
|
+
|
|
153
|
+
# Also handle allOf by merging all schemas
|
|
154
|
+
if simplify_unions and "allOf" in obj:
|
|
155
|
+
all_of = obj["allOf"]
|
|
156
|
+
if isinstance(all_of, list):
|
|
157
|
+
merged = {}
|
|
158
|
+
merged_properties = {}
|
|
159
|
+
for item in all_of:
|
|
160
|
+
if isinstance(item, dict):
|
|
161
|
+
resolved_item = resolve_refs(item, simplify_unions)
|
|
162
|
+
# Deep merge properties dicts
|
|
163
|
+
if "properties" in resolved_item:
|
|
164
|
+
merged_properties.update(
|
|
165
|
+
resolved_item.pop("properties")
|
|
166
|
+
)
|
|
167
|
+
merged.update(resolved_item)
|
|
168
|
+
if merged_properties:
|
|
169
|
+
merged["properties"] = merged_properties
|
|
170
|
+
# Keep other fields from original object (except allOf)
|
|
171
|
+
for k, v in obj.items():
|
|
172
|
+
if k != "allOf":
|
|
173
|
+
merged[k] = v
|
|
174
|
+
return resolve_refs(merged, simplify_unions)
|
|
75
175
|
|
|
76
176
|
# Check for $ref
|
|
77
177
|
if "$ref" in obj:
|
|
@@ -111,34 +211,23 @@ def _inline_refs(
|
|
|
111
211
|
):
|
|
112
212
|
continue
|
|
113
213
|
|
|
114
|
-
#
|
|
115
|
-
if
|
|
214
|
+
# Skip additionalProperties (not supported by Gemini or Claude)
|
|
215
|
+
if simplify_unions and key == "additionalProperties":
|
|
116
216
|
continue
|
|
117
217
|
|
|
118
|
-
#
|
|
119
|
-
|
|
120
|
-
if
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
new_key = "one_of"
|
|
125
|
-
elif key == "allOf":
|
|
126
|
-
new_key = "all_of"
|
|
127
|
-
elif key == "additionalProperties":
|
|
128
|
-
new_key = "additional_properties"
|
|
129
|
-
|
|
130
|
-
result[new_key] = resolve_refs(
|
|
131
|
-
value, convert_unions, simplify_for_claude
|
|
132
|
-
)
|
|
218
|
+
# Skip any remaining union type keys that weren't simplified above
|
|
219
|
+
# (This shouldn't happen normally, but just in case)
|
|
220
|
+
if simplify_unions and key in ("anyOf", "oneOf", "allOf"):
|
|
221
|
+
continue
|
|
222
|
+
|
|
223
|
+
result[key] = resolve_refs(value, simplify_unions)
|
|
133
224
|
return result
|
|
134
225
|
elif isinstance(obj, list):
|
|
135
|
-
return [
|
|
136
|
-
resolve_refs(item, convert_unions, simplify_for_claude) for item in obj
|
|
137
|
-
]
|
|
226
|
+
return [resolve_refs(item, simplify_unions) for item in obj]
|
|
138
227
|
else:
|
|
139
228
|
return obj
|
|
140
229
|
|
|
141
|
-
return resolve_refs(schema,
|
|
230
|
+
return resolve_refs(schema, simplify_unions)
|
|
142
231
|
|
|
143
232
|
|
|
144
233
|
class UnwrappedResponse(httpx.Response):
|
|
@@ -405,15 +494,14 @@ class AntigravityClient(httpx.AsyncClient):
|
|
|
405
494
|
)
|
|
406
495
|
|
|
407
496
|
# Inline $refs and remove $defs from parameters
|
|
408
|
-
#
|
|
409
|
-
#
|
|
497
|
+
# Simplify union types (anyOf/oneOf/allOf) for BOTH Gemini and Claude
|
|
498
|
+
# Neither API supports union types in function schemas!
|
|
410
499
|
if "parameters" in func_decl:
|
|
411
500
|
is_gemini = "gemini" in model.lower()
|
|
412
501
|
is_claude = "claude" in model.lower()
|
|
413
502
|
func_decl["parameters"] = _inline_refs(
|
|
414
503
|
func_decl["parameters"],
|
|
415
|
-
|
|
416
|
-
simplify_for_claude=is_claude,
|
|
504
|
+
simplify_unions=(is_gemini or is_claude),
|
|
417
505
|
)
|
|
418
506
|
|
|
419
507
|
# Fix generationConfig for Antigravity compatibility
|
|
@@ -21,7 +21,10 @@ from .config import (
|
|
|
21
21
|
get_token_storage_path,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
# Proactive refresh buffer: refresh tokens 1 hour before expiration
|
|
25
|
+
# This ensures smooth operation by refreshing during model requests,
|
|
26
|
+
# well before the token actually expires
|
|
27
|
+
TOKEN_REFRESH_BUFFER_SECONDS = 3600 # 1 hour
|
|
25
28
|
|
|
26
29
|
logger = logging.getLogger(__name__)
|
|
27
30
|
|
|
@@ -121,6 +121,67 @@ def patch_process_message_history() -> None:
|
|
|
121
121
|
pass
|
|
122
122
|
|
|
123
123
|
|
|
124
|
+
def patch_tool_call_json_repair() -> None:
|
|
125
|
+
"""Patch pydantic-ai's _call_tool to auto-repair malformed JSON arguments.
|
|
126
|
+
|
|
127
|
+
LLMs sometimes produce slightly broken JSON in tool calls (trailing commas,
|
|
128
|
+
missing quotes, etc.). This patch intercepts tool calls and runs json_repair
|
|
129
|
+
on the arguments before validation, preventing unnecessary retries.
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
import json_repair
|
|
133
|
+
from pydantic_ai._tool_manager import ToolManager
|
|
134
|
+
|
|
135
|
+
# Store the original method
|
|
136
|
+
_original_call_tool = ToolManager._call_tool
|
|
137
|
+
|
|
138
|
+
async def _patched_call_tool(
|
|
139
|
+
self,
|
|
140
|
+
call,
|
|
141
|
+
*,
|
|
142
|
+
allow_partial: bool,
|
|
143
|
+
wrap_validation_errors: bool,
|
|
144
|
+
approved: bool,
|
|
145
|
+
):
|
|
146
|
+
"""Patched _call_tool that repairs malformed JSON before validation."""
|
|
147
|
+
# Only attempt repair if args is a string (JSON)
|
|
148
|
+
if isinstance(call.args, str) and call.args:
|
|
149
|
+
try:
|
|
150
|
+
repaired = json_repair.repair_json(call.args)
|
|
151
|
+
if repaired != call.args:
|
|
152
|
+
# JSON was repaired! Log and update
|
|
153
|
+
try:
|
|
154
|
+
from rich.console import Console
|
|
155
|
+
console = Console(stderr=True)
|
|
156
|
+
console.print(
|
|
157
|
+
"[bold yellow]🐕 WOOF! Repaired malformed tool call JSON! AWOOOOOOOOOO![/]"
|
|
158
|
+
)
|
|
159
|
+
except ImportError:
|
|
160
|
+
pass # No rich console available
|
|
161
|
+
|
|
162
|
+
# Update the call args with repaired JSON
|
|
163
|
+
call.args = repaired
|
|
164
|
+
except Exception:
|
|
165
|
+
pass # If repair fails, let original validation handle it
|
|
166
|
+
|
|
167
|
+
# Call the original method
|
|
168
|
+
return await _original_call_tool(
|
|
169
|
+
self,
|
|
170
|
+
call,
|
|
171
|
+
allow_partial=allow_partial,
|
|
172
|
+
wrap_validation_errors=wrap_validation_errors,
|
|
173
|
+
approved=approved,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Apply the patch
|
|
177
|
+
ToolManager._call_tool = _patched_call_tool
|
|
178
|
+
|
|
179
|
+
except ImportError:
|
|
180
|
+
pass # json_repair or pydantic_ai not available
|
|
181
|
+
except Exception:
|
|
182
|
+
pass # Don't crash on patch failure
|
|
183
|
+
|
|
184
|
+
|
|
124
185
|
def apply_all_patches() -> None:
|
|
125
186
|
"""Apply all pydantic-ai monkey patches.
|
|
126
187
|
|
|
@@ -129,3 +190,4 @@ def apply_all_patches() -> None:
|
|
|
129
190
|
patch_user_agent()
|
|
130
191
|
patch_message_history_cleaning()
|
|
131
192
|
patch_process_message_history()
|
|
193
|
+
patch_tool_call_json_repair()
|
|
@@ -4,15 +4,14 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-puppy"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.368"
|
|
8
8
|
description = "Code generation agent"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11,<3.14"
|
|
11
11
|
dependencies = [
|
|
12
|
-
"pydantic-ai-slim[openai,anthropic]==1.
|
|
12
|
+
"pydantic-ai-slim[openai,anthropic]==1.26.0",
|
|
13
13
|
"typer>=0.12.0",
|
|
14
|
-
"mcp>=1.9.4",
|
|
15
|
-
|
|
14
|
+
"mcp>=1.9.4",
|
|
16
15
|
"httpx[http2]>=0.24.1",
|
|
17
16
|
"requests>=2.28.0",
|
|
18
17
|
"rich>=13.4.2",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|