code-puppy 0.0.315__tar.gz → 0.0.317__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.315 → code_puppy-0.0.317}/PKG-INFO +1 -1
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/base_agent.py +25 -30
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/cli_runner.py +6 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/blocking_startup.py +11 -3
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/managed_server.py +22 -2
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/manager.py +65 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/__init__.py +9 -0
- code_puppy-0.0.317/code_puppy/messaging/markdown_patches.py +57 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/model_factory.py +6 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/pyproject.toml +2 -1
- {code_puppy-0.0.315 → code_puppy-0.0.317}/.gitignore +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/LICENSE +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/README.md +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_python_programmer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/agents/prompt_reviewer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/add_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/config.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/main.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/models.json +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/prompts/codex_system_prompt.md +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/camoufox_manager.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/browser/vqa_agent.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/version_checker.py +0 -0
|
@@ -47,11 +47,10 @@ from code_puppy.config import (
|
|
|
47
47
|
get_protected_token_count,
|
|
48
48
|
get_use_dbos,
|
|
49
49
|
get_value,
|
|
50
|
-
load_mcp_server_configs,
|
|
51
50
|
)
|
|
52
51
|
from code_puppy.error_logging import log_error
|
|
53
52
|
from code_puppy.keymap import cancel_agent_uses_signal, get_cancel_agent_char_code
|
|
54
|
-
from code_puppy.mcp_ import
|
|
53
|
+
from code_puppy.mcp_ import get_mcp_manager
|
|
55
54
|
from code_puppy.messaging import (
|
|
56
55
|
emit_error,
|
|
57
56
|
emit_info,
|
|
@@ -90,6 +89,9 @@ class BaseAgent(ABC):
|
|
|
90
89
|
# Cache for MCP tool definitions (for token estimation)
|
|
91
90
|
# This is populated after the first successful run when MCP tools are retrieved
|
|
92
91
|
self._mcp_tool_definitions_cache: List[Dict[str, Any]] = []
|
|
92
|
+
# Shared console for streaming output - should be set by cli_runner
|
|
93
|
+
# to avoid conflicts between spinner's Live display and response streaming
|
|
94
|
+
self._console: Optional[Any] = None
|
|
93
95
|
|
|
94
96
|
@property
|
|
95
97
|
@abstractmethod
|
|
@@ -989,45 +991,31 @@ class BaseAgent(ABC):
|
|
|
989
991
|
return self._puppy_rules
|
|
990
992
|
|
|
991
993
|
def load_mcp_servers(self, extra_headers: Optional[Dict[str, str]] = None):
|
|
992
|
-
"""Load MCP servers through the manager and return pydantic-ai compatible servers.
|
|
994
|
+
"""Load MCP servers through the manager and return pydantic-ai compatible servers.
|
|
995
|
+
|
|
996
|
+
Note: The manager automatically syncs from mcp_servers.json during initialization,
|
|
997
|
+
so we don't need to sync here. Use reload_mcp_servers() to force a re-sync.
|
|
998
|
+
"""
|
|
993
999
|
|
|
994
1000
|
mcp_disabled = get_value("disable_mcp_servers")
|
|
995
1001
|
if mcp_disabled and str(mcp_disabled).lower() in ("1", "true", "yes", "on"):
|
|
996
1002
|
return []
|
|
997
1003
|
|
|
998
1004
|
manager = get_mcp_manager()
|
|
999
|
-
configs = load_mcp_server_configs()
|
|
1000
|
-
if not configs:
|
|
1001
|
-
existing_servers = manager.list_servers()
|
|
1002
|
-
if not existing_servers:
|
|
1003
|
-
return []
|
|
1004
|
-
else:
|
|
1005
|
-
for name, conf in configs.items():
|
|
1006
|
-
try:
|
|
1007
|
-
server_config = ServerConfig(
|
|
1008
|
-
id=conf.get("id", f"{name}_{hash(name)}"),
|
|
1009
|
-
name=name,
|
|
1010
|
-
type=conf.get("type", "sse"),
|
|
1011
|
-
enabled=conf.get("enabled", True),
|
|
1012
|
-
config=conf,
|
|
1013
|
-
)
|
|
1014
|
-
existing = manager.get_server_by_name(name)
|
|
1015
|
-
if not existing:
|
|
1016
|
-
manager.register_server(server_config)
|
|
1017
|
-
else:
|
|
1018
|
-
if existing.config != server_config.config:
|
|
1019
|
-
manager.update_server(existing.id, server_config)
|
|
1020
|
-
except Exception:
|
|
1021
|
-
continue
|
|
1022
|
-
|
|
1023
1005
|
return manager.get_servers_for_agent()
|
|
1024
1006
|
|
|
1025
1007
|
def reload_mcp_servers(self):
|
|
1026
|
-
"""Reload MCP servers and return updated servers.
|
|
1008
|
+
"""Reload MCP servers and return updated servers.
|
|
1009
|
+
|
|
1010
|
+
Forces a re-sync from mcp_servers.json to pick up any configuration changes.
|
|
1011
|
+
"""
|
|
1027
1012
|
# Clear the MCP tool cache when servers are reloaded
|
|
1028
1013
|
self._mcp_tool_definitions_cache = []
|
|
1029
|
-
|
|
1014
|
+
|
|
1015
|
+
# Force re-sync from mcp_servers.json
|
|
1030
1016
|
manager = get_mcp_manager()
|
|
1017
|
+
manager.sync_from_config()
|
|
1018
|
+
|
|
1031
1019
|
return manager.get_servers_for_agent()
|
|
1032
1020
|
|
|
1033
1021
|
def _load_model_with_fallback(
|
|
@@ -1291,7 +1279,14 @@ class BaseAgent(ABC):
|
|
|
1291
1279
|
|
|
1292
1280
|
from code_puppy.messaging.spinner import pause_all_spinners
|
|
1293
1281
|
|
|
1294
|
-
console
|
|
1282
|
+
# IMPORTANT: Use the shared console (set by cli_runner) to avoid conflicts
|
|
1283
|
+
# with the spinner's Live display. Multiple Console instances with separate
|
|
1284
|
+
# Live displays cause cursor positioning chaos and line duplication.
|
|
1285
|
+
if self._console is not None:
|
|
1286
|
+
console = self._console
|
|
1287
|
+
else:
|
|
1288
|
+
# Fallback if console not set (shouldn't happen in normal use)
|
|
1289
|
+
console = Console()
|
|
1295
1290
|
|
|
1296
1291
|
# Disable Live display in test mode or non-interactive environments
|
|
1297
1292
|
# This fixes issues with pexpect PTY where Live() hangs
|
|
@@ -706,6 +706,12 @@ async def run_prompt_with_attachments(
|
|
|
706
706
|
attachments = [attachment.content for attachment in processed_prompt.attachments]
|
|
707
707
|
link_attachments = [link.url_part for link in processed_prompt.link_attachments]
|
|
708
708
|
|
|
709
|
+
# IMPORTANT: Set the shared console on the agent so that streaming output
|
|
710
|
+
# uses the same console as the spinner. This prevents Live display conflicts
|
|
711
|
+
# that cause line duplication during markdown streaming.
|
|
712
|
+
if spinner_console is not None:
|
|
713
|
+
agent._console = spinner_console
|
|
714
|
+
|
|
709
715
|
# Create the agent task first so we can track and cancel it
|
|
710
716
|
agent_task = asyncio.create_task(
|
|
711
717
|
agent.run_with_mcp(
|
|
@@ -201,15 +201,23 @@ class BlockingMCPServerStdio(SimpleCapturedMCPServerStdio):
|
|
|
201
201
|
|
|
202
202
|
return result
|
|
203
203
|
|
|
204
|
-
except
|
|
204
|
+
except BaseException as e:
|
|
205
205
|
# Store error and mark as initialized (with error)
|
|
206
|
-
|
|
206
|
+
# Unwrap ExceptionGroup if present (Python 3.11+)
|
|
207
|
+
if type(e).__name__ == "ExceptionGroup" and hasattr(e, "exceptions"):
|
|
208
|
+
# Use the first exception as the primary cause
|
|
209
|
+
self._init_error = e.exceptions[0]
|
|
210
|
+
error_details = f"{e.exceptions[0]}"
|
|
211
|
+
else:
|
|
212
|
+
self._init_error = e
|
|
213
|
+
error_details = str(e)
|
|
214
|
+
|
|
207
215
|
self._initialized.set()
|
|
208
216
|
|
|
209
217
|
# Emit error message
|
|
210
218
|
server_name = getattr(self, "tool_prefix", self.command)
|
|
211
219
|
emit_info(
|
|
212
|
-
f"❌ MCP Server '{server_name}' failed to initialize: {
|
|
220
|
+
f"❌ MCP Server '{server_name}' failed to initialize: {error_details}",
|
|
213
221
|
style="red",
|
|
214
222
|
message_group=self.message_group,
|
|
215
223
|
)
|
|
@@ -6,6 +6,7 @@ that adds management capabilities while maintaining 100% compatibility.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
|
+
import os
|
|
9
10
|
import uuid
|
|
10
11
|
from dataclasses import dataclass, field
|
|
11
12
|
from datetime import datetime, timedelta
|
|
@@ -222,7 +223,16 @@ class ManagedMCPServer:
|
|
|
222
223
|
if "read_timeout" in config:
|
|
223
224
|
http_kwargs["read_timeout"] = config["read_timeout"]
|
|
224
225
|
if "headers" in config:
|
|
225
|
-
|
|
226
|
+
# Expand environment variables in headers
|
|
227
|
+
headers = config.get("headers")
|
|
228
|
+
resolved_headers = {}
|
|
229
|
+
if isinstance(headers, dict):
|
|
230
|
+
for k, v in headers.items():
|
|
231
|
+
if isinstance(v, str):
|
|
232
|
+
resolved_headers[k] = os.path.expandvars(v)
|
|
233
|
+
else:
|
|
234
|
+
resolved_headers[k] = v
|
|
235
|
+
http_kwargs["headers"] = resolved_headers
|
|
226
236
|
# Create HTTP client if headers are provided but no client specified
|
|
227
237
|
|
|
228
238
|
self._pydantic_server = MCPServerStreamableHTTP(
|
|
@@ -243,8 +253,18 @@ class ManagedMCPServer:
|
|
|
243
253
|
Configured async HTTP client with custom headers
|
|
244
254
|
"""
|
|
245
255
|
headers = self.config.config.get("headers", {})
|
|
256
|
+
|
|
257
|
+
# Expand environment variables in headers
|
|
258
|
+
resolved_headers = {}
|
|
259
|
+
if isinstance(headers, dict):
|
|
260
|
+
for k, v in headers.items():
|
|
261
|
+
if isinstance(v, str):
|
|
262
|
+
resolved_headers[k] = os.path.expandvars(v)
|
|
263
|
+
else:
|
|
264
|
+
resolved_headers[k] = v
|
|
265
|
+
|
|
246
266
|
timeout = self.config.config.get("timeout", 30)
|
|
247
|
-
client = create_async_client(headers=
|
|
267
|
+
client = create_async_client(headers=resolved_headers, timeout=timeout)
|
|
248
268
|
return client
|
|
249
269
|
|
|
250
270
|
def enable(self) -> None:
|
|
@@ -78,11 +78,76 @@ class MCPManager:
|
|
|
78
78
|
# Active managed servers (server_id -> ManagedMCPServer)
|
|
79
79
|
self._managed_servers: Dict[str, ManagedMCPServer] = {}
|
|
80
80
|
|
|
81
|
+
# Sync servers from mcp_servers.json into registry
|
|
82
|
+
self.sync_from_config()
|
|
83
|
+
|
|
81
84
|
# Load existing servers from registry
|
|
82
85
|
self._initialize_servers()
|
|
83
86
|
|
|
84
87
|
logger.info("MCPManager initialized with core components")
|
|
85
88
|
|
|
89
|
+
def sync_from_config(self) -> None:
|
|
90
|
+
"""Sync servers from mcp_servers.json into the registry.
|
|
91
|
+
|
|
92
|
+
This public method ensures that servers defined in the user's
|
|
93
|
+
configuration file are automatically registered with the manager.
|
|
94
|
+
It can be called during initialization or manually to reload
|
|
95
|
+
server configurations.
|
|
96
|
+
|
|
97
|
+
This is the single source of truth for syncing mcp_servers.json
|
|
98
|
+
into the registry, avoiding duplication with base_agent.py.
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
from code_puppy.config import load_mcp_server_configs
|
|
102
|
+
|
|
103
|
+
configs = load_mcp_server_configs()
|
|
104
|
+
if not configs:
|
|
105
|
+
logger.debug("No servers found in mcp_servers.json")
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
synced_count = 0
|
|
109
|
+
updated_count = 0
|
|
110
|
+
|
|
111
|
+
for name, conf in configs.items():
|
|
112
|
+
try:
|
|
113
|
+
# Create ServerConfig from the loaded configuration
|
|
114
|
+
server_config = ServerConfig(
|
|
115
|
+
id=conf.get("id", ""), # Empty ID will be auto-generated
|
|
116
|
+
name=name,
|
|
117
|
+
type=conf.get("type", "sse"),
|
|
118
|
+
enabled=conf.get("enabled", True),
|
|
119
|
+
config=conf,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Check if server already exists by name
|
|
123
|
+
existing = self.registry.get_by_name(name)
|
|
124
|
+
|
|
125
|
+
if not existing:
|
|
126
|
+
# Register new server
|
|
127
|
+
self.registry.register(server_config)
|
|
128
|
+
synced_count += 1
|
|
129
|
+
logger.debug(f"Synced new server from config: {name}")
|
|
130
|
+
else:
|
|
131
|
+
# Update existing server if config has changed
|
|
132
|
+
if existing.config != server_config.config:
|
|
133
|
+
server_config.id = existing.id # Keep existing ID
|
|
134
|
+
self.registry.update(existing.id, server_config)
|
|
135
|
+
updated_count += 1
|
|
136
|
+
logger.debug(f"Updated server from config: {name}")
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
logger.warning(f"Failed to sync server '{name}' from config: {e}")
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
if synced_count > 0 or updated_count > 0:
|
|
143
|
+
logger.info(
|
|
144
|
+
f"Synced {synced_count} new and updated {updated_count} servers from mcp_servers.json"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
logger.error(f"Failed to sync from mcp_servers.json: {e}")
|
|
149
|
+
# Don't fail initialization if sync fails
|
|
150
|
+
|
|
86
151
|
def _initialize_servers(self) -> None:
|
|
87
152
|
"""Initialize managed servers from registry configurations."""
|
|
88
153
|
configs = self.registry.list_all()
|
|
@@ -29,6 +29,13 @@ Example (new):
|
|
|
29
29
|
>>> bus.emit(TextMessage(level=MessageLevel.INFO, text="Hello"))
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
+
# =============================================================================
|
|
33
|
+
# Apply Rich Markdown patches (left-justified headers)
|
|
34
|
+
# =============================================================================
|
|
35
|
+
from .markdown_patches import patch_markdown_headings
|
|
36
|
+
|
|
37
|
+
patch_markdown_headings()
|
|
38
|
+
|
|
32
39
|
# =============================================================================
|
|
33
40
|
# Legacy API (backward compatible)
|
|
34
41
|
# =============================================================================
|
|
@@ -220,4 +227,6 @@ __all__ = [
|
|
|
220
227
|
"RichConsoleRenderer",
|
|
221
228
|
"DEFAULT_STYLES",
|
|
222
229
|
"DIFF_STYLES",
|
|
230
|
+
# Markdown patches
|
|
231
|
+
"patch_markdown_headings",
|
|
223
232
|
]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Patches for Rich's Markdown rendering.
|
|
2
|
+
|
|
3
|
+
This module provides customizations to Rich's default Markdown rendering,
|
|
4
|
+
particularly for header justification which is hardcoded to center in Rich.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from rich import box
|
|
8
|
+
from rich.markdown import Heading, Markdown
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from rich.text import Text
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LeftJustifiedHeading(Heading):
|
|
14
|
+
"""A heading that left-justifies text instead of centering.
|
|
15
|
+
|
|
16
|
+
Rich's default Heading class hardcodes `text.justify = 'center'`,
|
|
17
|
+
which can look odd in a CLI context. This subclass overrides that
|
|
18
|
+
to use left justification instead.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __rich_console__(self, console, options):
|
|
22
|
+
"""Render the heading with left justification."""
|
|
23
|
+
text = self.text
|
|
24
|
+
text.justify = "left" # Override Rich's default 'center'
|
|
25
|
+
|
|
26
|
+
if self.tag == "h1":
|
|
27
|
+
# Draw a border around h1s (same as Rich default)
|
|
28
|
+
yield Panel(
|
|
29
|
+
text,
|
|
30
|
+
box=box.HEAVY,
|
|
31
|
+
style="markdown.h1.border",
|
|
32
|
+
)
|
|
33
|
+
else:
|
|
34
|
+
# Styled text for h2 and beyond (same as Rich default)
|
|
35
|
+
if self.tag == "h2":
|
|
36
|
+
yield Text("")
|
|
37
|
+
yield text
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
_patched = False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def patch_markdown_headings():
|
|
44
|
+
"""Patch Rich's Markdown to use left-justified headings.
|
|
45
|
+
|
|
46
|
+
This function is idempotent - calling it multiple times has no effect
|
|
47
|
+
after the first call.
|
|
48
|
+
"""
|
|
49
|
+
global _patched
|
|
50
|
+
if _patched:
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
Markdown.elements["heading_open"] = LeftJustifiedHeading
|
|
54
|
+
_patched = True
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
__all__ = ["patch_markdown_headings", "LeftJustifiedHeading"]
|
|
@@ -108,6 +108,12 @@ def make_model_settings(
|
|
|
108
108
|
# Handle Anthropic extended thinking settings
|
|
109
109
|
# Remove top_p as Anthropic doesn't support it with extended thinking
|
|
110
110
|
model_settings_dict.pop("top_p", None)
|
|
111
|
+
|
|
112
|
+
# Claude extended thinking requires temperature=1.0 (API restriction)
|
|
113
|
+
# Default to 1.0 if not explicitly set by user
|
|
114
|
+
if model_settings_dict.get("temperature") is None:
|
|
115
|
+
model_settings_dict["temperature"] = 1.0
|
|
116
|
+
|
|
111
117
|
extended_thinking = effective_settings.get("extended_thinking", True)
|
|
112
118
|
budget_tokens = effective_settings.get("budget_tokens", 10000)
|
|
113
119
|
if extended_thinking and budget_tokens:
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-puppy"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.317"
|
|
8
8
|
description = "Code generation agent"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11,<3.14"
|
|
@@ -79,6 +79,7 @@ path = "code_puppy/models_dev_api.json"
|
|
|
79
79
|
[tool.ruff.lint.per-file-ignores]
|
|
80
80
|
"code_puppy/main.py" = ["E402"]
|
|
81
81
|
"code_puppy/cli_runner.py" = ["E402"]
|
|
82
|
+
"code_puppy/messaging/__init__.py" = ["E402"]
|
|
82
83
|
|
|
83
84
|
[tool.pytest.ini_options]
|
|
84
85
|
addopts = "--cov=code_puppy --cov-report=term-missing"
|
|
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.315 → code_puppy-0.0.317}/code_puppy/command_line/load_context_completion.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/mcp/catalog_server_installer.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/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
|
|
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.315 → code_puppy-0.0.317}/code_puppy/command_line/model_picker_completion.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/command_line/prompt_toolkit_completion.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
|
|
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.315 → code_puppy-0.0.317}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py
RENAMED
|
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.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/register_callbacks.py
RENAMED
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/claude_code_oauth/test_plugin.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/customizable_commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/example_custom_command/README.md
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/file_permission_handler/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/shell_safety/agent_shell_safety.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.315 → code_puppy-0.0.317}/code_puppy/plugins/shell_safety/register_callbacks.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
|
|
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
|