code-puppy 0.0.802__tar.gz → 0.0.804__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.802 → code_puppy-0.0.804}/PKG-INFO +1 -1
- code_puppy-0.0.804/code_puppy/_pydantic_tool_helpers.py +103 -0
- code_puppy-0.0.804/code_puppy/private_inference.py +114 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/pydantic_patches.py +30 -127
- {code_puppy-0.0.802 → code_puppy-0.0.804}/pyproject.toml +1 -1
- {code_puppy-0.0.802 → code_puppy-0.0.804}/.gitignore +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/LICENSE +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/README.md +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agent_execution_context.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_builder.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_compaction.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_diagnostics.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_history.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_key_listeners.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_model_message_transform.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_non_streaming_render.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_output_limits.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_run_signals.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_runtime.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_steer_processor.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/_subagent_recursion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_helios.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_model_judge.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/agent_web_retriever.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/retry_profiles.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/run_stats.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/smooth_stream.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/atomic_io.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/atomic_json.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/cli_runner.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/add_model_details.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/autosave_search.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/completers.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/completion_cache.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/config_apply.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/file_index.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/help_catalog.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/help_overlay.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/image_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/mcp_servers_store.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/trust_command.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp_binding_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/menu_session.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/model_settings_defs.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/pagination.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/session_browser.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/session_browser_data.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/set_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/set_menu_catalog.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/set_menu_schema.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/set_menu_settings.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/set_menu_shims.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/set_menu_values.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/shell_passthrough.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/skills_completion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/tui_style.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/uc_menu.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/config.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/config_file.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/diagnostics.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/gemini_model.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/README.md +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/aliases.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/engine.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/executor.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/matcher.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/models.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/registry.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/hook_engine/validator.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/http_retry.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/httpx2_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/audit.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/catalog.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/formats.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/locale.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/locales/en-US.json +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/locales/es.json +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/locales/fr-CA.json +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/plurals.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/pseudo.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/i18n/translate.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/kennel_provider.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/list_filtering.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/main.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/agent_bindings.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/project_config.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/tool_arg_coercion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_/toolset_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_prompts/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/mcp_prompts/hook_creator.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/bar_painters.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/bar_rendering.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/bottom_bar.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/chords.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/editor_actions.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/editor_completion.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/editor_display.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/editor_history.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/editor_keys.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/editor_paste.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/external_editor.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/inline_bar.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/line_editor.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/pause_controller.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/prompt_prefix_style.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/run_ui.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/run_ui_wiring.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/subagent_console.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/messaging/transcript_guard.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/model_descriptions.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/model_switching.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/models.json +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/observability.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/platform_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/plugins/config.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/plugins/oauth_pasteback.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/plugins/trust.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/plugins/trust_notice.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/provider_credentials.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/provider_identity.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/secret_store.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/secret_store_backends.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/session_format_migration.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/session_lifecycle.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/session_migration.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/session_surrogate_unpickler.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/skill_provider.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/splash.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/token_usage.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/apply_patch.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/constants.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/handler.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/models.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/registration.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/renderers.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/theme.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_locator_resolver.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_manager.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_page_snapshot.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_semantic_interactions.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/browser/tool_registry.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/file_permission_state.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/fs_access.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/image_tools.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/io_backends.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/model_tools.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/shell_backgrounding.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/skills_tools.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/subagent_invocation.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/subagent_usage_metrics.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/tools/universal_constructor.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/undo_manager.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/universal_constructor_provider.py +0 -0
- {code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/version_checker.py +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Small, dependency-light helpers for Code Puppy's pydantic-ai tool patch."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
_CLAUDE_CODE_TOOL_PREFIX = "cp_"
|
|
8
|
+
_CLAUDE_CODE_MODEL_PREFIX = "claude-code"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _writeback_tool_args(call: Any, tool_args: dict, mode: str | None) -> None:
|
|
12
|
+
"""Persist pre-tool callback argument mutations onto ``call.args``.
|
|
13
|
+
|
|
14
|
+
Failures are swallowed because writeback must never block tool execution.
|
|
15
|
+
"""
|
|
16
|
+
if mode is None:
|
|
17
|
+
return
|
|
18
|
+
try:
|
|
19
|
+
if mode == "str":
|
|
20
|
+
import json
|
|
21
|
+
|
|
22
|
+
call.args = json.dumps(tool_args)
|
|
23
|
+
elif mode == "dict":
|
|
24
|
+
call.args = tool_args
|
|
25
|
+
except Exception:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _tool_args_for_pre_tool_call(call_args: Any) -> tuple[dict, str | None]:
|
|
30
|
+
"""Build a best-effort repaired dict view for pre-tool callbacks."""
|
|
31
|
+
if isinstance(call_args, dict):
|
|
32
|
+
return call_args, "dict"
|
|
33
|
+
if not isinstance(call_args, str):
|
|
34
|
+
return {}, None
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
import json
|
|
38
|
+
import json_repair
|
|
39
|
+
|
|
40
|
+
parsed = json.loads(json_repair.repair_json(call_args))
|
|
41
|
+
if isinstance(parsed, dict):
|
|
42
|
+
return parsed, "str"
|
|
43
|
+
except Exception:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
return {"raw": call_args}, None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _normalize_claude_code_tool_name(tool_manager: Any, name: Any) -> Any:
|
|
50
|
+
"""Resolve a wire-prefixed name against this run's actual tool registry."""
|
|
51
|
+
if not isinstance(name, str) or not name.startswith(_CLAUDE_CODE_TOOL_PREFIX):
|
|
52
|
+
return name
|
|
53
|
+
|
|
54
|
+
unprefixed = name[len(_CLAUDE_CODE_TOOL_PREFIX) :]
|
|
55
|
+
tools = getattr(tool_manager, "tools", None)
|
|
56
|
+
if isinstance(tools, dict):
|
|
57
|
+
# A real ``cp_*`` tool wins. Otherwise, normalize when the unprefixed
|
|
58
|
+
# name exists in this run — including private agents whose model may
|
|
59
|
+
# differ from the globally selected interactive model.
|
|
60
|
+
if name in tools:
|
|
61
|
+
return name
|
|
62
|
+
if unprefixed in tools:
|
|
63
|
+
return unprefixed
|
|
64
|
+
|
|
65
|
+
# Compatibility fallback for the brief window before a ToolManager has a
|
|
66
|
+
# prepared registry. Keep this scoped so unrelated providers can own
|
|
67
|
+
# legitimate ``cp_*`` names.
|
|
68
|
+
try:
|
|
69
|
+
from code_puppy.config import get_global_model_name
|
|
70
|
+
|
|
71
|
+
model_name = get_global_model_name() or ""
|
|
72
|
+
if model_name.startswith(_CLAUDE_CODE_MODEL_PREFIX):
|
|
73
|
+
return unprefixed
|
|
74
|
+
except Exception:
|
|
75
|
+
pass
|
|
76
|
+
return name
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
_GENERIC_BLOCK_REASON = "Tool execution blocked by hook"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _block_reason(callback_result: dict) -> str:
|
|
83
|
+
"""Render a hook's deny reason without ever turning a deny into an allow."""
|
|
84
|
+
try:
|
|
85
|
+
raw = (
|
|
86
|
+
callback_result.get("error_message") or callback_result.get("reason") or ""
|
|
87
|
+
)
|
|
88
|
+
if not isinstance(raw, str):
|
|
89
|
+
raw = str(raw)
|
|
90
|
+
marker = raw.find("[BLOCKED]")
|
|
91
|
+
if marker != -1:
|
|
92
|
+
return raw[marker:].strip() or _GENERIC_BLOCK_REASON
|
|
93
|
+
return raw.strip() or _GENERIC_BLOCK_REASON
|
|
94
|
+
except Exception:
|
|
95
|
+
return _GENERIC_BLOCK_REASON
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
__all__ = [
|
|
99
|
+
"_block_reason",
|
|
100
|
+
"_normalize_claude_code_tool_name",
|
|
101
|
+
"_tool_args_for_pre_tool_call",
|
|
102
|
+
"_writeback_tool_args",
|
|
103
|
+
]
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Private, one-shot model inference without the conversational agent runtime."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from typing import TypeVar
|
|
8
|
+
|
|
9
|
+
from pydantic_ai import Agent, UsageLimits
|
|
10
|
+
|
|
11
|
+
from code_puppy.model_factory import (
|
|
12
|
+
ModelFactory,
|
|
13
|
+
_is_anthropic_model,
|
|
14
|
+
make_model_settings,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
OutputT = TypeVar("OutputT")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _disable_chat_template_thinking(model_settings: dict[str, object]) -> None:
|
|
21
|
+
"""Disable an already-configured vLLM/SGLang thinking switch in place.
|
|
22
|
+
|
|
23
|
+
``chat_template_kwargs`` is not part of the OpenAI API. Only preserve and
|
|
24
|
+
override it when model configuration already opted into that extension;
|
|
25
|
+
injecting it for providers such as ChatGPT OAuth causes a 400 response.
|
|
26
|
+
"""
|
|
27
|
+
configured_extra_body = model_settings.get("extra_body")
|
|
28
|
+
if not isinstance(configured_extra_body, dict):
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
configured_chat_template = configured_extra_body.get("chat_template_kwargs")
|
|
32
|
+
if not isinstance(configured_chat_template, dict):
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
extra_body = dict(configured_extra_body)
|
|
36
|
+
chat_template_kwargs = dict(configured_chat_template)
|
|
37
|
+
chat_template_kwargs["enable_thinking"] = False
|
|
38
|
+
extra_body["chat_template_kwargs"] = chat_template_kwargs
|
|
39
|
+
model_settings["extra_body"] = extra_body
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _disable_anthropic_thinking(
|
|
43
|
+
model_name: str,
|
|
44
|
+
model_config: dict[str, object],
|
|
45
|
+
model_settings: dict[str, object],
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Explicitly override thinking embedded in Anthropic model defaults."""
|
|
48
|
+
if not _is_anthropic_model(model_name, model_config):
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
model_settings["anthropic_thinking"] = {"type": "disabled"}
|
|
52
|
+
|
|
53
|
+
# Plugin-created Anthropic models carry their own default settings. Agent
|
|
54
|
+
# settings are merged shallowly over those defaults, so explicitly replace
|
|
55
|
+
# extra_body as well or a model-level output_config.effort survives after
|
|
56
|
+
# thinking is disabled.
|
|
57
|
+
extra_body = dict(model_settings.get("extra_body") or {})
|
|
58
|
+
output_config = dict(extra_body.get("output_config") or {})
|
|
59
|
+
output_config.pop("effort", None)
|
|
60
|
+
if output_config:
|
|
61
|
+
extra_body["output_config"] = output_config
|
|
62
|
+
else:
|
|
63
|
+
extra_body.pop("output_config", None)
|
|
64
|
+
model_settings["extra_body"] = extra_body
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def run_private_prompt(
|
|
68
|
+
*,
|
|
69
|
+
model_name: str,
|
|
70
|
+
instructions: str,
|
|
71
|
+
prompt: str,
|
|
72
|
+
output_type: type[OutputT],
|
|
73
|
+
model_settings_overrides: Mapping[str, object] | None = None,
|
|
74
|
+
max_tokens: int = 256,
|
|
75
|
+
timeout_seconds: float = 30,
|
|
76
|
+
) -> OutputT:
|
|
77
|
+
"""Run one structured request without agent hooks, history, tools, or output.
|
|
78
|
+
|
|
79
|
+
Callers own policy for failures: safety checks may fail closed while
|
|
80
|
+
convenience classifiers may fail open.
|
|
81
|
+
"""
|
|
82
|
+
models_config = ModelFactory.load_config()
|
|
83
|
+
if model_name not in models_config:
|
|
84
|
+
raise ValueError(f"Unknown private-inference model: {model_name}")
|
|
85
|
+
|
|
86
|
+
model = ModelFactory.get_model(model_name, models_config)
|
|
87
|
+
model_settings = make_model_settings(
|
|
88
|
+
model_name,
|
|
89
|
+
max_tokens=max_tokens,
|
|
90
|
+
overrides=dict(model_settings_overrides or {}),
|
|
91
|
+
)
|
|
92
|
+
_disable_chat_template_thinking(model_settings)
|
|
93
|
+
_disable_anthropic_thinking(
|
|
94
|
+
model_name,
|
|
95
|
+
models_config[model_name],
|
|
96
|
+
model_settings,
|
|
97
|
+
)
|
|
98
|
+
agent = Agent(
|
|
99
|
+
model=model,
|
|
100
|
+
instructions=instructions,
|
|
101
|
+
output_type=output_type,
|
|
102
|
+
retries=0,
|
|
103
|
+
toolsets=[],
|
|
104
|
+
model_settings=model_settings,
|
|
105
|
+
)
|
|
106
|
+
async with asyncio.timeout(timeout_seconds):
|
|
107
|
+
result = await agent.run(
|
|
108
|
+
prompt,
|
|
109
|
+
usage_limits=UsageLimits(request_limit=1),
|
|
110
|
+
)
|
|
111
|
+
return result.output
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
__all__ = ["run_private_prompt"]
|
|
@@ -25,6 +25,13 @@ import logging
|
|
|
25
25
|
import warnings
|
|
26
26
|
from typing import Any
|
|
27
27
|
|
|
28
|
+
from code_puppy._pydantic_tool_helpers import (
|
|
29
|
+
_block_reason,
|
|
30
|
+
_normalize_claude_code_tool_name,
|
|
31
|
+
_tool_args_for_pre_tool_call,
|
|
32
|
+
_writeback_tool_args,
|
|
33
|
+
)
|
|
34
|
+
|
|
28
35
|
logger = logging.getLogger(__name__)
|
|
29
36
|
|
|
30
37
|
# Loud failures recorded during the current apply_all_patches() run, so the
|
|
@@ -184,91 +191,6 @@ def patch_tool_call_json_repair() -> bool:
|
|
|
184
191
|
)
|
|
185
192
|
|
|
186
193
|
|
|
187
|
-
def _writeback_tool_args(call: Any, tool_args: dict, mode: str | None) -> None:
|
|
188
|
-
"""Persist pre_tool_call mutations of ``tool_args`` back onto ``call.args``.
|
|
189
|
-
|
|
190
|
-
pydantic-ai's ``ToolCallPart.args`` is usually a JSON *string* (what the
|
|
191
|
-
LLM emitted). The pre_tool_call hook contract gives plugins a *dict* view
|
|
192
|
-
to mutate. Without this writeback, mutations vanish before the real tool
|
|
193
|
-
runs and the model sees nothing changed.
|
|
194
|
-
|
|
195
|
-
Args:
|
|
196
|
-
call: The ``ToolCallPart`` (or compatible) whose ``args`` we update.
|
|
197
|
-
tool_args: The dict view that hooks may have mutated.
|
|
198
|
-
mode: ``"str"`` to re-serialize as JSON, ``"dict"`` to assign directly,
|
|
199
|
-
or ``None`` to skip (unparseable input — don't corrupt it).
|
|
200
|
-
|
|
201
|
-
Failures are swallowed: writeback must never block tool execution.
|
|
202
|
-
"""
|
|
203
|
-
if mode is None:
|
|
204
|
-
return
|
|
205
|
-
try:
|
|
206
|
-
if mode == "str":
|
|
207
|
-
import json
|
|
208
|
-
|
|
209
|
-
call.args = json.dumps(tool_args)
|
|
210
|
-
elif mode == "dict":
|
|
211
|
-
call.args = tool_args
|
|
212
|
-
except Exception:
|
|
213
|
-
pass # never block tool execution on writeback failure
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def _tool_args_for_pre_tool_call(call_args: Any) -> tuple[dict, str | None]:
|
|
217
|
-
"""Build a best-effort repaired dict view for ``pre_tool_call`` hooks.
|
|
218
|
-
|
|
219
|
-
Editors now use model-native names (notably ``edit`` and ``apply_patch``),
|
|
220
|
-
so JSON repair belongs at this shared seam instead of in a
|
|
221
|
-
``replace_in_file``-specific path.
|
|
222
|
-
"""
|
|
223
|
-
if isinstance(call_args, dict):
|
|
224
|
-
return call_args, "dict"
|
|
225
|
-
if not isinstance(call_args, str):
|
|
226
|
-
return {}, None
|
|
227
|
-
|
|
228
|
-
try:
|
|
229
|
-
import json
|
|
230
|
-
import json_repair
|
|
231
|
-
|
|
232
|
-
parsed = json.loads(json_repair.repair_json(call_args))
|
|
233
|
-
if isinstance(parsed, dict):
|
|
234
|
-
return parsed, "str"
|
|
235
|
-
except Exception:
|
|
236
|
-
pass
|
|
237
|
-
|
|
238
|
-
# Keep the diagnostic view, but do not write it back and corrupt history.
|
|
239
|
-
return {"raw": call_args}, None
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
#: Shown when a hook denies without a usable reason, or when producing its
|
|
243
|
-
#: reason fails. A deny always renders as a deny — never as an allow.
|
|
244
|
-
_GENERIC_BLOCK_REASON = "Tool execution blocked by hook"
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def _block_reason(callback_result: dict) -> str:
|
|
248
|
-
"""Render a hook's deny reason, tolerating any value it supplied.
|
|
249
|
-
|
|
250
|
-
`error_message`/`reason` come from plugin code and are not guaranteed to be
|
|
251
|
-
strings. A non-string previously raised inside the caller's broad `except`,
|
|
252
|
-
which silently turned an explicit deny into an allow.
|
|
253
|
-
|
|
254
|
-
Total by construction: extraction is inside the guard too, because `.get`
|
|
255
|
-
and the truthiness of a plugin's own object can raise just as easily as
|
|
256
|
-
`__str__`, and none of that may escape into the caller.
|
|
257
|
-
"""
|
|
258
|
-
try:
|
|
259
|
-
raw = (
|
|
260
|
-
callback_result.get("error_message") or callback_result.get("reason") or ""
|
|
261
|
-
)
|
|
262
|
-
if not isinstance(raw, str):
|
|
263
|
-
raw = str(raw)
|
|
264
|
-
marker = raw.find("[BLOCKED]")
|
|
265
|
-
if marker != -1:
|
|
266
|
-
return raw[marker:].strip() or _GENERIC_BLOCK_REASON
|
|
267
|
-
return raw.strip() or _GENERIC_BLOCK_REASON
|
|
268
|
-
except Exception:
|
|
269
|
-
return _GENERIC_BLOCK_REASON
|
|
270
|
-
|
|
271
|
-
|
|
272
194
|
def patch_tool_call_callbacks() -> bool:
|
|
273
195
|
"""Patch pydantic-ai tool handling to support callbacks and Claude Code tool names.
|
|
274
196
|
|
|
@@ -277,12 +199,13 @@ def patch_tool_call_callbacks() -> bool:
|
|
|
277
199
|
``_call_tool`` is too late: prefixed tools get marked as ``unknown`` and can
|
|
278
200
|
burn through result retries, eventually raising ``UnexpectedModelBehavior``.
|
|
279
201
|
|
|
280
|
-
This patch normalizes Claude Code tool names early (during
|
|
281
|
-
validation, before classification) and wraps
|
|
282
|
-
single execution entry point since pydantic-ai
|
|
283
|
-
execution in the public
|
|
284
|
-
|
|
285
|
-
callbacks defined in
|
|
202
|
+
This patch normalizes Claude Code tool names early (during regular and
|
|
203
|
+
structured-output validation, before classification) and wraps
|
|
204
|
+
``execute_tool_call`` (the single execution entry point since pydantic-ai
|
|
205
|
+
split validation from execution in the public
|
|
206
|
+
``pydantic_ai.tool_manager`` module) so every tool invocation also triggers
|
|
207
|
+
the ``pre_tool_call`` and ``post_tool_call`` callbacks defined in
|
|
208
|
+
``code_puppy.callbacks``.
|
|
286
209
|
|
|
287
210
|
Why not the v2 ``Hooks`` capability? Evaluated against pydantic-ai
|
|
288
211
|
2.31.0 and rejected:
|
|
@@ -305,43 +228,13 @@ def patch_tool_call_callbacks() -> bool:
|
|
|
305
228
|
|
|
306
229
|
_original_execute_tool_call = ToolManager.execute_tool_call
|
|
307
230
|
_original_get_tool_def = ToolManager.get_tool_def
|
|
231
|
+
_original_validate_output_tool_call = ToolManager.validate_output_tool_call
|
|
308
232
|
_original_validate_tool_call = ToolManager.validate_tool_call
|
|
309
233
|
|
|
310
|
-
|
|
311
|
-
# unconditional stripping would corrupt legit ``cp_`` names from other types.
|
|
312
|
-
TOOL_PREFIX = "cp_"
|
|
313
|
-
# Matches claude_code_oauth's model-name convention (prompt_handler.py).
|
|
314
|
-
_CLAUDE_CODE_MODEL_PREFIX = "claude-code"
|
|
315
|
-
|
|
316
|
-
def _is_claude_code_model_active() -> bool:
|
|
317
|
-
"""Best-effort check: is the currently selected model a claude-code one?
|
|
318
|
-
|
|
319
|
-
Lazy-imported so this patch stays safe to apply before config is
|
|
320
|
-
initialised; any failure means "not claude-code" so we never
|
|
321
|
-
accidentally strip prefixes from non-claude-code tool names.
|
|
322
|
-
"""
|
|
323
|
-
try:
|
|
324
|
-
from code_puppy.config import get_global_model_name
|
|
325
|
-
|
|
326
|
-
model_name = get_global_model_name() or ""
|
|
327
|
-
return model_name.startswith(_CLAUDE_CODE_MODEL_PREFIX)
|
|
328
|
-
except Exception:
|
|
329
|
-
return False
|
|
330
|
-
|
|
331
|
-
def _normalize_tool_name(name: Any) -> Any:
|
|
332
|
-
"""Strip the ``cp_`` prefix if present (claude-code models only)."""
|
|
333
|
-
if (
|
|
334
|
-
isinstance(name, str)
|
|
335
|
-
and name.startswith(TOOL_PREFIX)
|
|
336
|
-
and _is_claude_code_model_active()
|
|
337
|
-
):
|
|
338
|
-
return name[len(TOOL_PREFIX) :]
|
|
339
|
-
return name
|
|
340
|
-
|
|
341
|
-
def _normalize_call_tool_name(call: Any) -> tuple[Any, Any]:
|
|
234
|
+
def _normalize_call_tool_name(self: Any, call: Any) -> tuple[Any, Any]:
|
|
342
235
|
"""Normalize the tool_name on a call object in-place."""
|
|
343
236
|
tool_name = getattr(call, "tool_name", None)
|
|
344
|
-
normalized_name =
|
|
237
|
+
normalized_name = _normalize_claude_code_tool_name(self, tool_name)
|
|
345
238
|
if normalized_name != tool_name:
|
|
346
239
|
try:
|
|
347
240
|
call.tool_name = normalized_name
|
|
@@ -353,18 +246,24 @@ def patch_tool_call_callbacks() -> bool:
|
|
|
353
246
|
# Run before classification so prefixed names resolve correctly.
|
|
354
247
|
|
|
355
248
|
def _patched_get_tool_def(self, name: str):
|
|
356
|
-
|
|
249
|
+
normalized_name = _normalize_claude_code_tool_name(self, name)
|
|
250
|
+
return _original_get_tool_def(self, normalized_name)
|
|
357
251
|
|
|
358
252
|
async def _patched_validate_tool_call(self, call, **kwargs):
|
|
359
253
|
"""Normalize the tool name before pydantic-ai classifies the call."""
|
|
360
|
-
_normalize_call_tool_name(call)
|
|
254
|
+
_normalize_call_tool_name(self, call)
|
|
361
255
|
return await _original_validate_tool_call(self, call, **kwargs)
|
|
362
256
|
|
|
257
|
+
async def _patched_validate_output_tool_call(self, call, **kwargs):
|
|
258
|
+
"""Normalize names used by structured result output tools."""
|
|
259
|
+
_normalize_call_tool_name(self, call)
|
|
260
|
+
return await _original_validate_output_tool_call(self, call, **kwargs)
|
|
261
|
+
|
|
363
262
|
# -- execute_tool_call wrapper with callbacks ----------------------------
|
|
364
263
|
|
|
365
264
|
async def _patched_execute_tool_call(self, validated, **kwargs):
|
|
366
265
|
call = validated.call
|
|
367
|
-
tool_name, call = _normalize_call_tool_name(call)
|
|
266
|
+
tool_name, call = _normalize_call_tool_name(self, call)
|
|
368
267
|
|
|
369
268
|
# Give hooks a dict view of the args. Prefer the already-validated
|
|
370
269
|
# dict — execution passes it to the tool, so in-place mutations
|
|
@@ -469,9 +368,13 @@ def patch_tool_call_callbacks() -> bool:
|
|
|
469
368
|
pass # never block tool execution
|
|
470
369
|
|
|
471
370
|
ToolManager.get_tool_def = _patched_get_tool_def
|
|
371
|
+
ToolManager.validate_output_tool_call = _patched_validate_output_tool_call
|
|
472
372
|
ToolManager.validate_tool_call = _patched_validate_tool_call
|
|
473
373
|
ToolManager.execute_tool_call = _patched_execute_tool_call
|
|
474
374
|
assert ToolManager.get_tool_def is _patched_get_tool_def
|
|
375
|
+
assert (
|
|
376
|
+
ToolManager.validate_output_tool_call is _patched_validate_output_tool_call
|
|
377
|
+
)
|
|
475
378
|
assert ToolManager.validate_tool_call is _patched_validate_tool_call
|
|
476
379
|
assert ToolManager.execute_tool_call is _patched_execute_tool_call
|
|
477
380
|
return True
|
|
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
|
|
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
|
|
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
|
|
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
|
{code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/load_context_completion.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/catalog_server_installer.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.802 → code_puppy-0.0.804}/code_puppy/command_line/mcp/custom_server_installer.py
RENAMED
|
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
|