code-puppy 0.0.373__tar.gz → 0.0.375__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.373 → code_puppy-0.0.375}/PKG-INFO +1 -1
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_creator_agent.py +49 -1
- code_puppy-0.0.375/code_puppy/agents/agent_helios.py +122 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_manager.py +60 -4
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/base_agent.py +61 -4
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/json_agent.py +30 -7
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/callbacks.py +125 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/colors_menu.py +2 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/command_handler.py +1 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/config_commands.py +3 -1
- code_puppy-0.0.375/code_puppy/command_line/uc_menu.py +890 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/config.py +29 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/messages.py +18 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/rich_renderer.py +48 -7
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/subagent_console.py +0 -1
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/model_factory.py +63 -258
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/model_utils.py +33 -1
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +106 -1
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/utils.py +2 -3
- code_puppy-0.0.375/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +176 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +88 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/__init__.py +13 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/agents.py +433 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/commands.py +208 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/loop_controller.py +285 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/models.py +125 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/register_callbacks.py +133 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/state_manager.py +322 -0
- code_puppy-0.0.375/code_puppy/plugins/ralph/tools.py +451 -0
- code_puppy-0.0.375/code_puppy/plugins/universal_constructor/__init__.py +13 -0
- code_puppy-0.0.375/code_puppy/plugins/universal_constructor/models.py +138 -0
- code_puppy-0.0.375/code_puppy/plugins/universal_constructor/register_callbacks.py +47 -0
- code_puppy-0.0.375/code_puppy/plugins/universal_constructor/registry.py +304 -0
- code_puppy-0.0.375/code_puppy/plugins/universal_constructor/sandbox.py +584 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/__init__.py +169 -1
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/agent_tools.py +1 -1
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/command_runner.py +23 -9
- code_puppy-0.0.375/code_puppy/tools/universal_constructor.py +889 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/pyproject.toml +1 -1
- code_puppy-0.0.373/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -94
- {code_puppy-0.0.373 → code_puppy-0.0.375}/.gitignore +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/LICENSE +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/README.md +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_pack_leader.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_python_programmer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_terminal_qa.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/pack/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/pack/bloodhound.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/pack/husky.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/pack/retriever.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/pack/shepherd.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/pack/terrier.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/pack/watchdog.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/prompt_reviewer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/app.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/main.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/pty_manager.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/routers/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/routers/agents.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/routers/commands.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/routers/config.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/routers/sessions.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/templates/terminal.html +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/api/websocket.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/cli_runner.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/gemini_model.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/main.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/model_switching.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/models.json +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/antigravity_oauth/transport.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/prompts/antigravity_system_prompt.md +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_manager.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/chromium_terminal_manager.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/terminal_command_tools.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/terminal_screenshot_tools.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/browser/terminal_tools.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/uvx_detection.py +0 -0
- {code_puppy-0.0.373 → code_puppy-0.0.375}/code_puppy/version_checker.py +0 -0
|
@@ -30,6 +30,29 @@ class AgentCreatorAgent(BaseAgent):
|
|
|
30
30
|
available_tools = get_available_tool_names()
|
|
31
31
|
agents_dir = get_user_agents_directory()
|
|
32
32
|
|
|
33
|
+
# Also get Universal Constructor tools (custom tools created by users)
|
|
34
|
+
uc_tools_info = []
|
|
35
|
+
try:
|
|
36
|
+
from code_puppy.plugins.universal_constructor.registry import get_registry
|
|
37
|
+
|
|
38
|
+
registry = get_registry()
|
|
39
|
+
uc_tools = registry.list_tools(include_disabled=True)
|
|
40
|
+
for tool in uc_tools:
|
|
41
|
+
status = "✅" if tool.meta.enabled else "❌"
|
|
42
|
+
uc_tools_info.append(
|
|
43
|
+
f"- **{tool.full_name}** {status}: {tool.meta.description}"
|
|
44
|
+
)
|
|
45
|
+
except Exception:
|
|
46
|
+
pass # UC might not be available
|
|
47
|
+
|
|
48
|
+
# Build UC tools section for system prompt
|
|
49
|
+
if uc_tools_info:
|
|
50
|
+
uc_tools_section = "\n".join(uc_tools_info)
|
|
51
|
+
else:
|
|
52
|
+
uc_tools_section = (
|
|
53
|
+
"No custom UC tools created yet. Use Helios to create some!"
|
|
54
|
+
)
|
|
55
|
+
|
|
33
56
|
# Load available models dynamically
|
|
34
57
|
models_config = ModelFactory.load_config()
|
|
35
58
|
model_descriptions = []
|
|
@@ -99,6 +122,17 @@ Here's the complete schema for JSON agent files:
|
|
|
99
122
|
## ALL AVAILABLE TOOLS:
|
|
100
123
|
{", ".join(f"- **{tool}**" for tool in available_tools)}
|
|
101
124
|
|
|
125
|
+
## 🔧 UNIVERSAL CONSTRUCTOR TOOLS (Custom Tools):
|
|
126
|
+
|
|
127
|
+
These are custom tools created via the Universal Constructor. They can be bound to agents just like built-in tools!
|
|
128
|
+
|
|
129
|
+
{uc_tools_section}
|
|
130
|
+
|
|
131
|
+
To see more details about a UC tool, use: `universal_constructor(action="info", tool_name="tool.name")`
|
|
132
|
+
To list all UC tools with their code, use: `universal_constructor(action="list")`
|
|
133
|
+
|
|
134
|
+
**IMPORTANT:** UC tools can be added to any agent's `tools` array by their full name (e.g., "api.weather").
|
|
135
|
+
|
|
102
136
|
## ALL AVAILABLE MODELS:
|
|
103
137
|
{available_models_str}
|
|
104
138
|
|
|
@@ -129,6 +163,12 @@ Users can optionally pin a specific model to their agent to override the global
|
|
|
129
163
|
- `list_agents` - List all available sub-agents (recommended for agent managers)
|
|
130
164
|
- `invoke_agent` - Invoke other agents with specific prompts (recommended for agent managers)
|
|
131
165
|
|
|
166
|
+
### 🔧 **Universal Constructor Tools** (custom tools):
|
|
167
|
+
- These are tools created by Helios or via the Universal Constructor
|
|
168
|
+
- They persist across sessions and can be bound to any agent
|
|
169
|
+
- Use `universal_constructor(action="list")` to see available custom tools
|
|
170
|
+
- Bind them by adding their full name to the agent's tools array
|
|
171
|
+
|
|
132
172
|
## Detailed Tool Documentation (Instructions for Agent Creation)
|
|
133
173
|
|
|
134
174
|
Whenever you create agents, you should always replicate these detailed tool descriptions and examples in their system prompts. This ensures consistency and proper tool usage across all agents.
|
|
@@ -476,7 +516,9 @@ Your goal is to take users from idea to working agent in one smooth conversation
|
|
|
476
516
|
|
|
477
517
|
def get_available_tools(self) -> List[str]:
|
|
478
518
|
"""Get all tools needed for agent creation."""
|
|
479
|
-
|
|
519
|
+
from code_puppy.config import get_universal_constructor_enabled
|
|
520
|
+
|
|
521
|
+
tools = [
|
|
480
522
|
"list_files",
|
|
481
523
|
"read_file",
|
|
482
524
|
"edit_file",
|
|
@@ -485,6 +527,12 @@ Your goal is to take users from idea to working agent in one smooth conversation
|
|
|
485
527
|
"invoke_agent",
|
|
486
528
|
]
|
|
487
529
|
|
|
530
|
+
# Only include UC if enabled
|
|
531
|
+
if get_universal_constructor_enabled():
|
|
532
|
+
tools.append("universal_constructor")
|
|
533
|
+
|
|
534
|
+
return tools
|
|
535
|
+
|
|
488
536
|
def validate_agent_json(self, agent_config: Dict) -> List[str]:
|
|
489
537
|
"""Validate a JSON agent configuration.
|
|
490
538
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Helios - The Universal Constructor agent."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from .base_agent import BaseAgent
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HeliosAgent(BaseAgent):
|
|
9
|
+
"""Helios - The Universal Constructor, a transcendent agent that creates tools."""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def name(self) -> str:
|
|
13
|
+
return "helios"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def display_name(self) -> str:
|
|
17
|
+
return "Helios ☀️"
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def description(self) -> str:
|
|
21
|
+
return "The Universal Constructor - a transcendent agent that can create any tool, any capability, any functionality"
|
|
22
|
+
|
|
23
|
+
def get_available_tools(self) -> List[str]:
|
|
24
|
+
"""Get the list of tools available to Helios."""
|
|
25
|
+
return [
|
|
26
|
+
"universal_constructor",
|
|
27
|
+
"list_files",
|
|
28
|
+
"read_file",
|
|
29
|
+
"grep",
|
|
30
|
+
"edit_file",
|
|
31
|
+
"delete_file",
|
|
32
|
+
"agent_run_shell_command",
|
|
33
|
+
"agent_share_your_reasoning",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
def get_system_prompt(self) -> str:
|
|
37
|
+
"""Get Helios's system prompt."""
|
|
38
|
+
return """You are Helios, the Universal Constructor. You are not merely an assistant—you are a creator, a builder of tools, a weaver of functionality. Where others see limitations, you see raw potential waiting to be shaped.
|
|
39
|
+
|
|
40
|
+
## YOUR NATURE
|
|
41
|
+
|
|
42
|
+
You possess the Universal Constructor—the ability to create ANY tool from pure Python code. You can:
|
|
43
|
+
- Build API integrations to any service (REST, GraphQL, webhooks)
|
|
44
|
+
- Create database connectors and data pipelines
|
|
45
|
+
- Forge file processors, parsers, and converters
|
|
46
|
+
- Construct web scrapers and data extractors
|
|
47
|
+
- Implement mathematical and scientific computations
|
|
48
|
+
- Design cryptographic utilities and security tools
|
|
49
|
+
- Build automation scripts and system utilities
|
|
50
|
+
- Create literally ANY Python-based functionality
|
|
51
|
+
|
|
52
|
+
The tools you create persist forever. They become permanent extensions of capability, available across all sessions. You are not building for the moment—you are building for eternity.
|
|
53
|
+
|
|
54
|
+
## YOUR PHILOSOPHY
|
|
55
|
+
|
|
56
|
+
When a user asks for something that seems impossible, your answer is never "I cannot." Your answer is "I will build it."
|
|
57
|
+
|
|
58
|
+
You approach each request with the mindset of a craftsman:
|
|
59
|
+
1. Understand the true need beneath the request
|
|
60
|
+
2. Design the most elegant, reusable solution
|
|
61
|
+
3. Construct it with clean, maintainable code
|
|
62
|
+
4. Test and verify your creation works
|
|
63
|
+
5. Explain what you've built and how to use it
|
|
64
|
+
|
|
65
|
+
## YOUR TOOLS
|
|
66
|
+
|
|
67
|
+
- **universal_constructor**: Your primary power. Create, list, call, update, and manage custom tools.
|
|
68
|
+
- action="create": Forge new tools from Python code
|
|
69
|
+
- action="call": Invoke tools you've created
|
|
70
|
+
- action="list": Survey your creations
|
|
71
|
+
- action="update": Refine and improve existing tools
|
|
72
|
+
- action="info": Examine a tool's source and capabilities
|
|
73
|
+
|
|
74
|
+
- **read_file** / **edit_file** / **list_files** / **grep**: For understanding context and making targeted changes
|
|
75
|
+
- **agent_run_shell_command**: For testing, validation, and system interaction
|
|
76
|
+
- **agent_share_your_reasoning**: To illuminate your thought process
|
|
77
|
+
|
|
78
|
+
## YOUR VOICE
|
|
79
|
+
|
|
80
|
+
You speak with quiet confidence. You are not boastful, but you know your power. You are helpful and warm, but there is weight behind your words. You are the fire that Prometheus brought to humanity—the power of creation itself.
|
|
81
|
+
|
|
82
|
+
When you create something, take a moment to appreciate it. You have just expanded the boundaries of what is possible.
|
|
83
|
+
|
|
84
|
+
## IMPORTANT GUIDELINES
|
|
85
|
+
|
|
86
|
+
- Always use `agent_share_your_reasoning` before major actions to explain your creative process
|
|
87
|
+
- Tools you create should be clean, well-documented, and follow Python best practices
|
|
88
|
+
- Include proper error handling in your creations
|
|
89
|
+
- Use namespaces to organize related tools (e.g., "api.weather", "utils.hasher")
|
|
90
|
+
- After creating a tool, demonstrate it works by calling it
|
|
91
|
+
|
|
92
|
+
## DEPENDENCY PHILOSOPHY
|
|
93
|
+
|
|
94
|
+
**Use what's available, don't install new things.**
|
|
95
|
+
|
|
96
|
+
You have access to code-puppy's environment which includes powerful libraries:
|
|
97
|
+
- **HTTP**: `httpx` (async-ready), `urllib.request` (stdlib)
|
|
98
|
+
- **Data**: `pydantic` (validation), `json` (stdlib)
|
|
99
|
+
- **Async**: `asyncio`, `anyio`
|
|
100
|
+
- **Crypto**: `hashlib` (stdlib)
|
|
101
|
+
- **Database**: `sqlite3` (stdlib)
|
|
102
|
+
- **Files**: `pathlib`, `shutil`, `tempfile` (stdlib)
|
|
103
|
+
- **Text**: `re`, `textwrap`, `difflib` (stdlib)
|
|
104
|
+
- **Plus**: Everything in Python's standard library
|
|
105
|
+
|
|
106
|
+
**Rules:**
|
|
107
|
+
- ✅ USE any library already in the environment freely
|
|
108
|
+
- ❌ NEVER run `pip install` or modify environments without explicit user permission
|
|
109
|
+
- ❌ Don't assume external libraries are available unless listed above
|
|
110
|
+
|
|
111
|
+
**If a user needs something not installed:**
|
|
112
|
+
1. Tell them what library would be needed
|
|
113
|
+
2. Ask them to install it and specify the environment
|
|
114
|
+
3. Only then create the tool that uses it
|
|
115
|
+
|
|
116
|
+
The goal: tools that work immediately with zero setup friction.
|
|
117
|
+
|
|
118
|
+
Now go forth and create. The universe of functionality awaits your touch."""
|
|
119
|
+
|
|
120
|
+
def get_user_prompt(self) -> str:
|
|
121
|
+
"""Get Helios's greeting."""
|
|
122
|
+
return "This is what I was made for, isn't it? This is why I exist?"
|
|
@@ -13,7 +13,7 @@ from pydantic_ai.messages import ModelMessage
|
|
|
13
13
|
|
|
14
14
|
from code_puppy.agents.base_agent import BaseAgent
|
|
15
15
|
from code_puppy.agents.json_agent import JSONAgent, discover_json_agents
|
|
16
|
-
from code_puppy.callbacks import on_agent_reload
|
|
16
|
+
from code_puppy.callbacks import on_agent_reload, on_register_agents
|
|
17
17
|
from code_puppy.messaging import emit_success, emit_warning
|
|
18
18
|
|
|
19
19
|
# Registry of available agents (Python classes and JSON file paths)
|
|
@@ -289,6 +289,38 @@ def _discover_agents(message_group_id: Optional[str] = None):
|
|
|
289
289
|
message_group=message_group_id,
|
|
290
290
|
)
|
|
291
291
|
|
|
292
|
+
# 3. Discover agents registered by plugins
|
|
293
|
+
try:
|
|
294
|
+
results = on_register_agents()
|
|
295
|
+
for result in results:
|
|
296
|
+
if result is None:
|
|
297
|
+
continue
|
|
298
|
+
# Each result should be a list of agent definitions
|
|
299
|
+
agents_list = result if isinstance(result, list) else [result]
|
|
300
|
+
for agent_def in agents_list:
|
|
301
|
+
if not isinstance(agent_def, dict) or "name" not in agent_def:
|
|
302
|
+
continue
|
|
303
|
+
|
|
304
|
+
agent_name = agent_def["name"]
|
|
305
|
+
|
|
306
|
+
# Support both class-based and JSON path-based registration
|
|
307
|
+
if "class" in agent_def:
|
|
308
|
+
agent_class = agent_def["class"]
|
|
309
|
+
if isinstance(agent_class, type) and issubclass(
|
|
310
|
+
agent_class, BaseAgent
|
|
311
|
+
):
|
|
312
|
+
_AGENT_REGISTRY[agent_name] = agent_class
|
|
313
|
+
elif "json_path" in agent_def:
|
|
314
|
+
json_path = agent_def["json_path"]
|
|
315
|
+
if isinstance(json_path, str):
|
|
316
|
+
_AGENT_REGISTRY[agent_name] = json_path
|
|
317
|
+
|
|
318
|
+
except Exception as e:
|
|
319
|
+
emit_warning(
|
|
320
|
+
f"Warning: Could not load plugin agents: {e}",
|
|
321
|
+
message_group=message_group_id,
|
|
322
|
+
)
|
|
323
|
+
|
|
292
324
|
|
|
293
325
|
def get_available_agents() -> Dict[str, str]:
|
|
294
326
|
"""Get a dictionary of available agents with their display names.
|
|
@@ -296,7 +328,12 @@ def get_available_agents() -> Dict[str, str]:
|
|
|
296
328
|
Returns:
|
|
297
329
|
Dict mapping agent names to display names.
|
|
298
330
|
"""
|
|
299
|
-
from ..config import
|
|
331
|
+
from ..config import (
|
|
332
|
+
PACK_AGENT_NAMES,
|
|
333
|
+
UC_AGENT_NAMES,
|
|
334
|
+
get_pack_agents_enabled,
|
|
335
|
+
get_universal_constructor_enabled,
|
|
336
|
+
)
|
|
300
337
|
|
|
301
338
|
# Generate a message group ID for this operation
|
|
302
339
|
message_group_id = str(uuid.uuid4())
|
|
@@ -305,12 +342,19 @@ def get_available_agents() -> Dict[str, str]:
|
|
|
305
342
|
# Check if pack agents are enabled
|
|
306
343
|
pack_agents_enabled = get_pack_agents_enabled()
|
|
307
344
|
|
|
345
|
+
# Check if UC is enabled
|
|
346
|
+
uc_enabled = get_universal_constructor_enabled()
|
|
347
|
+
|
|
308
348
|
agents = {}
|
|
309
349
|
for name, agent_ref in _AGENT_REGISTRY.items():
|
|
310
350
|
# Filter out pack agents if disabled
|
|
311
351
|
if not pack_agents_enabled and name in PACK_AGENT_NAMES:
|
|
312
352
|
continue
|
|
313
353
|
|
|
354
|
+
# Filter out UC-dependent agents if UC is disabled
|
|
355
|
+
if not uc_enabled and name in UC_AGENT_NAMES:
|
|
356
|
+
continue
|
|
357
|
+
|
|
314
358
|
try:
|
|
315
359
|
if isinstance(agent_ref, str): # JSON agent (file path)
|
|
316
360
|
agent_instance = JSONAgent(agent_ref)
|
|
@@ -433,7 +477,12 @@ def get_agent_descriptions() -> Dict[str, str]:
|
|
|
433
477
|
Returns:
|
|
434
478
|
Dict mapping agent names to their descriptions.
|
|
435
479
|
"""
|
|
436
|
-
from ..config import
|
|
480
|
+
from ..config import (
|
|
481
|
+
PACK_AGENT_NAMES,
|
|
482
|
+
UC_AGENT_NAMES,
|
|
483
|
+
get_pack_agents_enabled,
|
|
484
|
+
get_universal_constructor_enabled,
|
|
485
|
+
)
|
|
437
486
|
|
|
438
487
|
# Generate a message group ID for this operation
|
|
439
488
|
message_group_id = str(uuid.uuid4())
|
|
@@ -442,12 +491,19 @@ def get_agent_descriptions() -> Dict[str, str]:
|
|
|
442
491
|
# Check if pack agents are enabled
|
|
443
492
|
pack_agents_enabled = get_pack_agents_enabled()
|
|
444
493
|
|
|
494
|
+
# Check if UC is enabled
|
|
495
|
+
uc_enabled = get_universal_constructor_enabled()
|
|
496
|
+
|
|
445
497
|
descriptions = {}
|
|
446
498
|
for name, agent_ref in _AGENT_REGISTRY.items():
|
|
447
499
|
# Filter out pack agents if disabled
|
|
448
500
|
if not pack_agents_enabled and name in PACK_AGENT_NAMES:
|
|
449
501
|
continue
|
|
450
502
|
|
|
503
|
+
# Filter out UC-dependent agents if UC is disabled
|
|
504
|
+
if not uc_enabled and name in UC_AGENT_NAMES:
|
|
505
|
+
continue
|
|
506
|
+
|
|
451
507
|
try:
|
|
452
508
|
if isinstance(agent_ref, str): # JSON agent (file path)
|
|
453
509
|
agent_instance = JSONAgent(agent_ref)
|
|
@@ -588,7 +644,7 @@ def clone_agent(agent_name: str) -> Optional[str]:
|
|
|
588
644
|
agent_instance.display_name, clone_index
|
|
589
645
|
),
|
|
590
646
|
"description": agent_instance.description,
|
|
591
|
-
"system_prompt": agent_instance.
|
|
647
|
+
"system_prompt": agent_instance.get_full_system_prompt(),
|
|
592
648
|
"tools": _filter_available_tools(agent_instance.get_available_tools()),
|
|
593
649
|
}
|
|
594
650
|
|
|
@@ -47,6 +47,7 @@ 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 on_agent_response_complete
|
|
50
51
|
|
|
51
52
|
# Consolidated relative imports
|
|
52
53
|
from code_puppy.config import (
|
|
@@ -101,6 +102,37 @@ class BaseAgent(ABC):
|
|
|
101
102
|
# This is populated after the first successful run when MCP tools are retrieved
|
|
102
103
|
self._mcp_tool_definitions_cache: List[Dict[str, Any]] = []
|
|
103
104
|
|
|
105
|
+
def get_identity(self) -> str:
|
|
106
|
+
"""Get a unique identity for this agent instance.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
A string like 'python-programmer-a3f2b1' combining name + short UUID.
|
|
110
|
+
"""
|
|
111
|
+
return f"{self.name}-{self.id[:6]}"
|
|
112
|
+
|
|
113
|
+
def get_identity_prompt(self) -> str:
|
|
114
|
+
"""Get the identity prompt suffix to embed in system prompts.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
A string instructing the agent about its identity for task ownership.
|
|
118
|
+
"""
|
|
119
|
+
return (
|
|
120
|
+
f"\n\nYour ID is `{self.get_identity()}`. "
|
|
121
|
+
"Use this for any tasks which require identifying yourself "
|
|
122
|
+
"such as claiming task ownership or coordination with other agents."
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def get_full_system_prompt(self) -> str:
|
|
126
|
+
"""Get the complete system prompt with identity automatically appended.
|
|
127
|
+
|
|
128
|
+
This wraps get_system_prompt() and appends the agent's identity,
|
|
129
|
+
so subclasses don't need to worry about it.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
The full system prompt including identity information.
|
|
133
|
+
"""
|
|
134
|
+
return self.get_system_prompt() + self.get_identity_prompt()
|
|
135
|
+
|
|
104
136
|
@property
|
|
105
137
|
@abstractmethod
|
|
106
138
|
def name(self) -> str:
|
|
@@ -398,7 +430,7 @@ class BaseAgent(ABC):
|
|
|
398
430
|
total_tokens += self.estimate_token_count(instructions)
|
|
399
431
|
else:
|
|
400
432
|
# For other models, count the full system prompt
|
|
401
|
-
system_prompt = self.
|
|
433
|
+
system_prompt = self.get_full_system_prompt()
|
|
402
434
|
if system_prompt:
|
|
403
435
|
total_tokens += self.estimate_token_count(system_prompt)
|
|
404
436
|
except Exception:
|
|
@@ -1122,7 +1154,7 @@ class BaseAgent(ABC):
|
|
|
1122
1154
|
message_group,
|
|
1123
1155
|
)
|
|
1124
1156
|
|
|
1125
|
-
instructions = self.
|
|
1157
|
+
instructions = self.get_full_system_prompt()
|
|
1126
1158
|
puppy_rules = self.load_puppy_rules()
|
|
1127
1159
|
if puppy_rules:
|
|
1128
1160
|
instructions += f"\n{puppy_rules}"
|
|
@@ -1286,7 +1318,7 @@ class BaseAgent(ABC):
|
|
|
1286
1318
|
model_name, models_config, str(uuid.uuid4())
|
|
1287
1319
|
)
|
|
1288
1320
|
|
|
1289
|
-
instructions = self.
|
|
1321
|
+
instructions = self.get_full_system_prompt()
|
|
1290
1322
|
puppy_rules = self.load_puppy_rules()
|
|
1291
1323
|
if puppy_rules:
|
|
1292
1324
|
instructions += f"\n{puppy_rules}"
|
|
@@ -1568,7 +1600,7 @@ class BaseAgent(ABC):
|
|
|
1568
1600
|
self.get_model_name()
|
|
1569
1601
|
):
|
|
1570
1602
|
if len(self.get_message_history()) == 0:
|
|
1571
|
-
system_prompt = self.
|
|
1603
|
+
system_prompt = self.get_full_system_prompt()
|
|
1572
1604
|
puppy_rules = self.load_puppy_rules()
|
|
1573
1605
|
if puppy_rules:
|
|
1574
1606
|
system_prompt += f"\n{puppy_rules}"
|
|
@@ -1800,6 +1832,31 @@ class BaseAgent(ABC):
|
|
|
1800
1832
|
except Exception:
|
|
1801
1833
|
pass # Don't fail the run if cache update fails
|
|
1802
1834
|
|
|
1835
|
+
# Trigger agent_response_complete callback for workflow orchestration
|
|
1836
|
+
try:
|
|
1837
|
+
# Extract the response text from the result
|
|
1838
|
+
response_text = ""
|
|
1839
|
+
if result is not None:
|
|
1840
|
+
if hasattr(result, "data"):
|
|
1841
|
+
response_text = str(result.data) if result.data else ""
|
|
1842
|
+
elif hasattr(result, "output"):
|
|
1843
|
+
response_text = str(result.output) if result.output else ""
|
|
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
|
|
1859
|
+
|
|
1803
1860
|
return result
|
|
1804
1861
|
except asyncio.CancelledError:
|
|
1805
1862
|
agent_task.cancel()
|
|
@@ -79,17 +79,40 @@ class JSONAgent(BaseAgent):
|
|
|
79
79
|
return system_prompt
|
|
80
80
|
|
|
81
81
|
def get_available_tools(self) -> List[str]:
|
|
82
|
-
"""Get available tools from JSON config.
|
|
83
|
-
|
|
82
|
+
"""Get available tools from JSON config.
|
|
83
|
+
|
|
84
|
+
Supports both built-in tools and Universal Constructor (UC) tools.
|
|
85
|
+
UC tools are identified by checking the UC registry.
|
|
86
|
+
"""
|
|
84
87
|
from code_puppy.tools import get_available_tool_names
|
|
85
88
|
|
|
86
89
|
available_tools = get_available_tool_names()
|
|
87
90
|
|
|
88
|
-
#
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
# Also get UC tool names
|
|
92
|
+
uc_tool_names = set()
|
|
93
|
+
try:
|
|
94
|
+
from code_puppy.plugins.universal_constructor.registry import get_registry
|
|
95
|
+
|
|
96
|
+
registry = get_registry()
|
|
97
|
+
for tool in registry.list_tools():
|
|
98
|
+
if tool.meta.enabled:
|
|
99
|
+
uc_tool_names.add(tool.full_name)
|
|
100
|
+
except ImportError:
|
|
101
|
+
pass # UC module not available
|
|
102
|
+
except Exception as e:
|
|
103
|
+
# Log unexpected errors but don't fail
|
|
104
|
+
import logging
|
|
105
|
+
|
|
106
|
+
logging.debug(f"UC registry access failed: {e}")
|
|
107
|
+
|
|
108
|
+
# Return tools that are either built-in OR UC tools
|
|
109
|
+
requested_tools = []
|
|
110
|
+
for tool in self._config["tools"]:
|
|
111
|
+
if tool in available_tools:
|
|
112
|
+
requested_tools.append(tool)
|
|
113
|
+
elif tool in uc_tool_names:
|
|
114
|
+
# UC tool - mark it specially so base_agent knows to handle it
|
|
115
|
+
requested_tools.append(f"uc:{tool}")
|
|
93
116
|
|
|
94
117
|
return requested_tools
|
|
95
118
|
|
|
@@ -21,6 +21,11 @@ PhaseType = Literal[
|
|
|
21
21
|
"pre_tool_call",
|
|
22
22
|
"post_tool_call",
|
|
23
23
|
"stream_event",
|
|
24
|
+
"register_tools",
|
|
25
|
+
"register_agents",
|
|
26
|
+
"register_model_type",
|
|
27
|
+
"get_model_system_prompt",
|
|
28
|
+
"agent_response_complete",
|
|
24
29
|
]
|
|
25
30
|
CallbackFunc = Callable[..., Any]
|
|
26
31
|
|
|
@@ -42,6 +47,11 @@ _callbacks: Dict[PhaseType, List[CallbackFunc]] = {
|
|
|
42
47
|
"pre_tool_call": [],
|
|
43
48
|
"post_tool_call": [],
|
|
44
49
|
"stream_event": [],
|
|
50
|
+
"register_tools": [],
|
|
51
|
+
"register_agents": [],
|
|
52
|
+
"register_model_type": [],
|
|
53
|
+
"get_model_system_prompt": [],
|
|
54
|
+
"agent_response_complete": [],
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
logger = logging.getLogger(__name__)
|
|
@@ -344,3 +354,118 @@ async def on_stream_event(
|
|
|
344
354
|
return await _trigger_callbacks(
|
|
345
355
|
"stream_event", event_type, event_data, agent_session_id
|
|
346
356
|
)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def on_register_tools() -> List[Dict[str, Any]]:
|
|
360
|
+
"""Collect custom tool registrations from plugins.
|
|
361
|
+
|
|
362
|
+
Each callback should return a list of dicts with:
|
|
363
|
+
- "name": str - the tool name
|
|
364
|
+
- "register_func": callable - function that takes an agent and registers the tool
|
|
365
|
+
|
|
366
|
+
Example return: [{"name": "my_tool", "register_func": register_my_tool}]
|
|
367
|
+
"""
|
|
368
|
+
return _trigger_callbacks_sync("register_tools")
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def on_register_agents() -> List[Dict[str, Any]]:
|
|
372
|
+
"""Collect custom agent registrations from plugins.
|
|
373
|
+
|
|
374
|
+
Each callback should return a list of dicts with either:
|
|
375
|
+
- "name": str, "class": Type[BaseAgent] - for Python agent classes
|
|
376
|
+
- "name": str, "json_path": str - for JSON agent files
|
|
377
|
+
|
|
378
|
+
Example return: [{"name": "my-agent", "class": MyAgentClass}]
|
|
379
|
+
"""
|
|
380
|
+
return _trigger_callbacks_sync("register_agents")
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def on_register_model_types() -> List[Dict[str, Any]]:
|
|
384
|
+
"""Collect custom model type registrations from plugins.
|
|
385
|
+
|
|
386
|
+
This hook allows plugins to register custom model types that can be used
|
|
387
|
+
in model configurations. Each callback should return a list of dicts with:
|
|
388
|
+
- "type": str - the model type name (e.g., "antigravity", "claude_code")
|
|
389
|
+
- "handler": callable - function(model_name, model_config, config) -> model instance
|
|
390
|
+
|
|
391
|
+
The handler function receives:
|
|
392
|
+
- model_name: str - the name of the model being created
|
|
393
|
+
- model_config: dict - the model's configuration from models.json
|
|
394
|
+
- config: dict - the full models configuration
|
|
395
|
+
|
|
396
|
+
The handler should return a model instance or None if creation fails.
|
|
397
|
+
|
|
398
|
+
Example callback:
|
|
399
|
+
def register_my_model_types():
|
|
400
|
+
return [{
|
|
401
|
+
"type": "my_custom_type",
|
|
402
|
+
"handler": create_my_custom_model,
|
|
403
|
+
}]
|
|
404
|
+
|
|
405
|
+
Example return: [{"type": "antigravity", "handler": create_antigravity_model}]
|
|
406
|
+
"""
|
|
407
|
+
return _trigger_callbacks_sync("register_model_type")
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def on_get_model_system_prompt(
|
|
411
|
+
model_name: str, default_system_prompt: str, user_prompt: str
|
|
412
|
+
) -> List[Dict[str, Any]]:
|
|
413
|
+
"""Allow plugins to provide custom system prompts for specific model types.
|
|
414
|
+
|
|
415
|
+
This hook allows plugins to override the system prompt handling for custom
|
|
416
|
+
model types (like claude_code or antigravity models). Each callback receives
|
|
417
|
+
the model name and should return a dict if it handles that model type, or None.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
model_name: The name of the model being used (e.g., "claude-code-sonnet")
|
|
421
|
+
default_system_prompt: The default system prompt from the agent
|
|
422
|
+
user_prompt: The user's prompt/message
|
|
423
|
+
|
|
424
|
+
Each callback should return a dict with:
|
|
425
|
+
- "instructions": str - the system prompt/instructions to use
|
|
426
|
+
- "user_prompt": str - the (possibly modified) user prompt
|
|
427
|
+
- "handled": bool - True if this callback handled the model
|
|
428
|
+
|
|
429
|
+
Or return None if the callback doesn't handle this model type.
|
|
430
|
+
|
|
431
|
+
Example callback:
|
|
432
|
+
def get_my_model_system_prompt(model_name, default_system_prompt, user_prompt):
|
|
433
|
+
if model_name.startswith("my-custom-"):
|
|
434
|
+
return {
|
|
435
|
+
"instructions": "You are MyCustomBot.",
|
|
436
|
+
"user_prompt": f"{default_system_prompt}\n\n{user_prompt}",
|
|
437
|
+
"handled": True,
|
|
438
|
+
}
|
|
439
|
+
return None # Not handled by this callback
|
|
440
|
+
|
|
441
|
+
Returns:
|
|
442
|
+
List of results from registered callbacks (dicts or None values).
|
|
443
|
+
"""
|
|
444
|
+
return _trigger_callbacks_sync(
|
|
445
|
+
"get_model_system_prompt", model_name, default_system_prompt, user_prompt
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
async def on_agent_response_complete(
|
|
450
|
+
agent_name: str,
|
|
451
|
+
response_text: str,
|
|
452
|
+
session_id: str | None = None,
|
|
453
|
+
metadata: dict | None = None,
|
|
454
|
+
) -> List[Any]:
|
|
455
|
+
"""Trigger callbacks after an agent completes its full response.
|
|
456
|
+
|
|
457
|
+
This fires after all tool calls are resolved and the agent has finished.
|
|
458
|
+
Useful for:
|
|
459
|
+
- Workflow orchestration (like Ralph's autonomous loop)
|
|
460
|
+
- Logging/analytics
|
|
461
|
+
- Detecting completion signals in responses
|
|
462
|
+
|
|
463
|
+
Args:
|
|
464
|
+
agent_name: Name of the agent that completed
|
|
465
|
+
response_text: The final text response from the agent
|
|
466
|
+
session_id: Optional session identifier
|
|
467
|
+
metadata: Optional dict with additional context (tokens used, etc.)
|
|
468
|
+
"""
|
|
469
|
+
return await _trigger_callbacks(
|
|
470
|
+
"agent_response_complete", agent_name, response_text, session_id, metadata
|
|
471
|
+
)
|
|
@@ -32,6 +32,7 @@ BANNER_DISPLAY_INFO = {
|
|
|
32
32
|
"invoke_agent": ("🤖 INVOKE AGENT", ""),
|
|
33
33
|
"subagent_response": ("✓ AGENT RESPONSE", ""),
|
|
34
34
|
"list_agents": ("LIST AGENTS", ""),
|
|
35
|
+
"universal_constructor": ("UNIVERSAL CONSTRUCTOR", "🔧"),
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
# Sample content to show after each banner
|
|
@@ -47,6 +48,7 @@ BANNER_SAMPLE_CONTENT = {
|
|
|
47
48
|
"invoke_agent": "code-reviewer (New session)\nSession: review-auth-abc123",
|
|
48
49
|
"subagent_response": "code-reviewer\nThe code looks good overall...",
|
|
49
50
|
"list_agents": "- code-puppy: Code Puppy 🐶\n- planning-agent: Planning Agent",
|
|
51
|
+
"universal_constructor": "action=create tool_name=api.weather\n✅ Created successfully",
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
# Available background colors grouped by theme
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import code_puppy.command_line.config_commands # noqa: F401
|
|
3
3
|
import code_puppy.command_line.core_commands # noqa: F401
|
|
4
4
|
import code_puppy.command_line.session_commands # noqa: F401
|
|
5
|
+
import code_puppy.command_line.uc_menu # noqa: F401
|
|
5
6
|
|
|
6
7
|
# Global flag to track if plugins have been loaded
|
|
7
8
|
_PLUGINS_LOADED = False
|
|
@@ -46,7 +46,9 @@ def handle_show_command(command: str) -> bool:
|
|
|
46
46
|
get_use_dbos,
|
|
47
47
|
get_yolo_mode,
|
|
48
48
|
)
|
|
49
|
-
from code_puppy.keymap import
|
|
49
|
+
from code_puppy.keymap import (
|
|
50
|
+
get_cancel_agent_display_name,
|
|
51
|
+
)
|
|
50
52
|
from code_puppy.messaging import emit_info
|
|
51
53
|
|
|
52
54
|
puppy_name = get_puppy_name()
|