code-puppy 0.0.378__tar.gz → 0.0.380__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.
Files changed (232) hide show
  1. {code_puppy-0.0.378 → code_puppy-0.0.380}/PKG-INFO +1 -1
  2. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/base_agent.py +76 -2
  3. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/callbacks.py +14 -0
  4. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/config.py +15 -0
  5. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/http_utils.py +39 -19
  6. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/server_registry_catalog.py +14 -1
  7. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/model_factory.py +6 -1
  8. {code_puppy-0.0.378 → code_puppy-0.0.380}/pyproject.toml +1 -1
  9. {code_puppy-0.0.378 → code_puppy-0.0.380}/.gitignore +0 -0
  10. {code_puppy-0.0.378 → code_puppy-0.0.380}/LICENSE +0 -0
  11. {code_puppy-0.0.378 → code_puppy-0.0.380}/README.md +0 -0
  12. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/__init__.py +0 -0
  13. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/__main__.py +0 -0
  14. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/__init__.py +0 -0
  15. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_c_reviewer.py +0 -0
  16. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_code_puppy.py +0 -0
  17. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_code_reviewer.py +0 -0
  18. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
  19. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_creator_agent.py +0 -0
  20. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_golang_reviewer.py +0 -0
  21. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_helios.py +0 -0
  22. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
  23. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_manager.py +0 -0
  24. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_pack_leader.py +0 -0
  25. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_planning.py +0 -0
  26. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_python_programmer.py +0 -0
  27. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_python_reviewer.py +0 -0
  28. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_qa_expert.py +0 -0
  29. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_qa_kitten.py +0 -0
  30. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_security_auditor.py +0 -0
  31. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_terminal_qa.py +0 -0
  32. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
  33. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/event_stream_handler.py +0 -0
  34. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/json_agent.py +0 -0
  35. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/pack/__init__.py +0 -0
  36. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/pack/bloodhound.py +0 -0
  37. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/pack/husky.py +0 -0
  38. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/pack/retriever.py +0 -0
  39. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/pack/shepherd.py +0 -0
  40. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/pack/terrier.py +0 -0
  41. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/pack/watchdog.py +0 -0
  42. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/prompt_reviewer.py +0 -0
  43. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/agents/subagent_stream_handler.py +0 -0
  44. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/__init__.py +0 -0
  45. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/app.py +0 -0
  46. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/main.py +0 -0
  47. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/pty_manager.py +0 -0
  48. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/routers/__init__.py +0 -0
  49. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/routers/agents.py +0 -0
  50. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/routers/commands.py +0 -0
  51. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/routers/config.py +0 -0
  52. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/routers/sessions.py +0 -0
  53. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/templates/terminal.html +0 -0
  54. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/api/websocket.py +0 -0
  55. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/chatgpt_codex_client.py +0 -0
  56. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/claude_cache_client.py +0 -0
  57. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/cli_runner.py +0 -0
  58. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/__init__.py +0 -0
  59. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/add_model_menu.py +0 -0
  60. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/agent_menu.py +0 -0
  61. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/attachments.py +0 -0
  62. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/autosave_menu.py +0 -0
  63. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/clipboard.py +0 -0
  64. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/colors_menu.py +0 -0
  65. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/command_handler.py +0 -0
  66. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/command_registry.py +0 -0
  67. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/config_commands.py +0 -0
  68. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/core_commands.py +0 -0
  69. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/diff_menu.py +0 -0
  70. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/file_path_completion.py +0 -0
  71. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/load_context_completion.py +0 -0
  72. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/__init__.py +0 -0
  73. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/base.py +0 -0
  74. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
  75. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  76. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
  77. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/edit_command.py +0 -0
  78. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/handler.py +0 -0
  79. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/help_command.py +0 -0
  80. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/install_command.py +0 -0
  81. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/install_menu.py +0 -0
  82. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/list_command.py +0 -0
  83. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/logs_command.py +0 -0
  84. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/remove_command.py +0 -0
  85. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/restart_command.py +0 -0
  86. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/search_command.py +0 -0
  87. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  88. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/start_command.py +0 -0
  89. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/status_command.py +0 -0
  90. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  91. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/stop_command.py +0 -0
  92. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/test_command.py +0 -0
  93. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/utils.py +0 -0
  94. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  95. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/mcp_completion.py +0 -0
  96. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/model_picker_completion.py +0 -0
  97. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/model_settings_menu.py +0 -0
  98. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/motd.py +0 -0
  99. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/onboarding_slides.py +0 -0
  100. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/onboarding_wizard.py +0 -0
  101. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/pin_command_completion.py +0 -0
  102. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  103. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/session_commands.py +0 -0
  104. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/uc_menu.py +0 -0
  105. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/command_line/utils.py +0 -0
  106. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/error_logging.py +0 -0
  107. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/gemini_code_assist.py +0 -0
  108. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/gemini_model.py +0 -0
  109. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/keymap.py +0 -0
  110. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/main.py +0 -0
  111. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/__init__.py +0 -0
  112. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/async_lifecycle.py +0 -0
  113. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/blocking_startup.py +0 -0
  114. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/captured_stdio_server.py +0 -0
  115. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/circuit_breaker.py +0 -0
  116. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/config_wizard.py +0 -0
  117. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/dashboard.py +0 -0
  118. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/error_isolation.py +0 -0
  119. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/examples/retry_example.py +0 -0
  120. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/health_monitor.py +0 -0
  121. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/managed_server.py +0 -0
  122. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/manager.py +0 -0
  123. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/mcp_logs.py +0 -0
  124. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/registry.py +0 -0
  125. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/retry_manager.py +0 -0
  126. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/status_tracker.py +0 -0
  127. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/mcp_/system_tools.py +0 -0
  128. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/__init__.py +0 -0
  129. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/bus.py +0 -0
  130. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/commands.py +0 -0
  131. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/markdown_patches.py +0 -0
  132. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/message_queue.py +0 -0
  133. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/messages.py +0 -0
  134. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/queue_console.py +0 -0
  135. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/renderers.py +0 -0
  136. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/rich_renderer.py +0 -0
  137. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/spinner/__init__.py +0 -0
  138. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/spinner/console_spinner.py +0 -0
  139. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/spinner/spinner_base.py +0 -0
  140. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/messaging/subagent_console.py +0 -0
  141. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/model_switching.py +0 -0
  142. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/model_utils.py +0 -0
  143. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/models.json +0 -0
  144. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/models_dev_api.json +0 -0
  145. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/models_dev_parser.py +0 -0
  146. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/__init__.py +0 -0
  147. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
  148. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
  149. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +0 -0
  150. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
  151. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
  152. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
  153. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +0 -0
  154. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
  155. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
  156. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
  157. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/transport.py +0 -0
  158. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/antigravity_oauth/utils.py +0 -0
  159. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
  160. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
  161. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
  162. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  163. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
  164. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
  165. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
  166. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
  167. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
  168. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
  169. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
  170. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
  171. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
  172. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
  173. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
  174. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
  175. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/example_custom_command/README.md +0 -0
  176. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
  177. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
  178. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
  179. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
  180. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
  181. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
  182. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/oauth_puppy_html.py +0 -0
  183. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/__init__.py +0 -0
  184. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/agents.py +0 -0
  185. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/commands.py +0 -0
  186. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/loop_controller.py +0 -0
  187. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/models.py +0 -0
  188. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/register_callbacks.py +0 -0
  189. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/state_manager.py +0 -0
  190. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/ralph/tools.py +0 -0
  191. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/shell_safety/__init__.py +0 -0
  192. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
  193. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
  194. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
  195. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
  196. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/universal_constructor/models.py +0 -0
  197. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
  198. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/universal_constructor/registry.py +0 -0
  199. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
  200. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/prompts/antigravity_system_prompt.md +0 -0
  201. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/pydantic_patches.py +0 -0
  202. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/reopenable_async_client.py +0 -0
  203. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/round_robin_model.py +0 -0
  204. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/session_storage.py +0 -0
  205. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/status_display.py +0 -0
  206. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/summarization_agent.py +0 -0
  207. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/terminal_utils.py +0 -0
  208. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/__init__.py +0 -0
  209. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/agent_tools.py +0 -0
  210. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/__init__.py +0 -0
  211. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_control.py +0 -0
  212. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_interactions.py +0 -0
  213. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_locators.py +0 -0
  214. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_manager.py +0 -0
  215. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_navigation.py +0 -0
  216. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  217. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_scripts.py +0 -0
  218. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/browser_workflows.py +0 -0
  219. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/chromium_terminal_manager.py +0 -0
  220. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/terminal_command_tools.py +0 -0
  221. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/terminal_screenshot_tools.py +0 -0
  222. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/browser/terminal_tools.py +0 -0
  223. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/command_runner.py +0 -0
  224. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/common.py +0 -0
  225. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/display.py +0 -0
  226. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/file_modifications.py +0 -0
  227. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/file_operations.py +0 -0
  228. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/subagent_context.py +0 -0
  229. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/tools_content.py +0 -0
  230. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/tools/universal_constructor.py +0 -0
  231. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/uvx_detection.py +0 -0
  232. {code_puppy-0.0.378 → code_puppy-0.0.380}/code_puppy/version_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.378
3
+ Version: 0.0.380
4
4
  Summary: Code generation agent
5
5
  Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
6
6
  Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
@@ -3,8 +3,11 @@
3
3
  import asyncio
4
4
  import json
5
5
  import math
6
+ import pathlib
6
7
  import signal
7
8
  import threading
9
+ import time
10
+ import traceback
8
11
  import uuid
9
12
  from abc import ABC, abstractmethod
10
13
  from typing import (
@@ -37,6 +40,7 @@ from pydantic_ai.durable_exec.dbos import DBOSAgent
37
40
  from pydantic_ai.messages import (
38
41
  ModelMessage,
39
42
  ModelRequest,
43
+ ModelResponse,
40
44
  TextPart,
41
45
  ThinkingPart,
42
46
  ToolCallPart,
@@ -88,6 +92,49 @@ _delayed_compaction_requested = False
88
92
  _reload_count = 0
89
93
 
90
94
 
95
+ def _log_error_to_file(exc: Exception) -> Optional[str]:
96
+ """Log detailed error information to ~/.code_puppy/error_logs/log_{timestamp}.txt.
97
+
98
+ Args:
99
+ exc: The exception to log.
100
+
101
+ Returns:
102
+ The path to the log file if successful, None otherwise.
103
+ """
104
+ try:
105
+ error_logs_dir = pathlib.Path.home() / ".code_puppy" / "error_logs"
106
+ error_logs_dir.mkdir(parents=True, exist_ok=True)
107
+
108
+ timestamp = time.strftime("%Y%m%d_%H%M%S")
109
+ log_file = error_logs_dir / f"log_{timestamp}.txt"
110
+
111
+ with open(log_file, "w", encoding="utf-8") as f:
112
+ f.write(f"Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
113
+ f.write(f"Exception Type: {type(exc).__name__}\n")
114
+ f.write(f"Exception Message: {str(exc)}\n")
115
+ f.write(f"Exception Args: {exc.args}\n")
116
+ f.write("\n--- Full Traceback ---\n")
117
+ f.write(traceback.format_exc())
118
+ f.write("\n--- Exception Chain ---\n")
119
+ # Walk the exception chain for chained exceptions
120
+ current = exc
121
+ chain_depth = 0
122
+ while current is not None and chain_depth < 10:
123
+ f.write(
124
+ f"\n[Cause {chain_depth}] {type(current).__name__}: {current}\n"
125
+ )
126
+ f.write("".join(traceback.format_tb(current.__traceback__)))
127
+ current = (
128
+ current.__cause__ if current.__cause__ else current.__context__
129
+ )
130
+ chain_depth += 1
131
+
132
+ return str(log_file)
133
+ except Exception:
134
+ # Don't let logging errors break the main flow
135
+ return None
136
+
137
+
91
138
  class BaseAgent(ABC):
92
139
  """Base class for all agent configurations."""
93
140
 
@@ -264,6 +311,33 @@ class BaseAgent(ABC):
264
311
  cleaned.append(message)
265
312
  return cleaned
266
313
 
314
+ def ensure_history_ends_with_request(
315
+ self, messages: List[ModelMessage]
316
+ ) -> List[ModelMessage]:
317
+ """Ensure message history ends with a ModelRequest.
318
+
319
+ pydantic_ai requires that processed message history ends with a ModelRequest.
320
+ This can fail when swapping models mid-conversation if the history ends with
321
+ a ModelResponse from the previous model.
322
+
323
+ This method trims trailing ModelResponse messages to ensure compatibility.
324
+
325
+ Args:
326
+ messages: List of messages to validate/fix.
327
+
328
+ Returns:
329
+ List of messages guaranteed to end with ModelRequest, or empty list
330
+ if no ModelRequest is found.
331
+ """
332
+ if not messages:
333
+ return messages
334
+
335
+ # Trim trailing ModelResponse messages
336
+ while messages and isinstance(messages[-1], ModelResponse):
337
+ messages = messages[:-1]
338
+
339
+ return messages
340
+
267
341
  # Message history processing methods (moved from state_management.py and message_history_processor.py)
268
342
  def _stringify_part(self, part: Any) -> str:
269
343
  """Create a stable string representation for a message part.
@@ -372,10 +446,10 @@ class BaseAgent(ABC):
372
446
 
373
447
  def estimate_token_count(self, text: str) -> int:
374
448
  """
375
- Simple token estimation using len(message) / 3.
449
+ Simple token estimation using len(message) / 2.5.
376
450
  This replaces tiktoken with a much simpler approach.
377
451
  """
378
- return max(1, math.floor((len(text) / 3)))
452
+ return max(1, math.floor((len(text) / 2.5)))
379
453
 
380
454
  def estimate_tokens_for_message(self, message: ModelMessage) -> int:
381
455
  """
@@ -27,6 +27,7 @@ PhaseType = Literal[
27
27
  "get_model_system_prompt",
28
28
  "agent_run_start",
29
29
  "agent_run_end",
30
+ "register_mcp_catalog_servers",
30
31
  ]
31
32
  CallbackFunc = Callable[..., Any]
32
33
 
@@ -54,6 +55,7 @@ _callbacks: Dict[PhaseType, List[CallbackFunc]] = {
54
55
  "get_model_system_prompt": [],
55
56
  "agent_run_start": [],
56
57
  "agent_run_end": [],
58
+ "register_mcp_catalog_servers": [],
57
59
  }
58
60
 
59
61
  logger = logging.getLogger(__name__)
@@ -517,3 +519,15 @@ async def on_agent_run_end(
517
519
  response_text,
518
520
  metadata,
519
521
  )
522
+
523
+
524
+ def on_register_mcp_catalog_servers() -> List[Any]:
525
+ """Trigger callbacks to register additional MCP catalog servers.
526
+
527
+ Plugins can register callbacks that return List[MCPServerTemplate] to add
528
+ servers to the MCP catalog/marketplace.
529
+
530
+ Returns:
531
+ List of results from all registered callbacks (each should be a list of MCPServerTemplate).
532
+ """
533
+ return _trigger_callbacks_sync("register_mcp_catalog_servers")
@@ -144,6 +144,19 @@ def set_universal_constructor_enabled(enabled: bool) -> None:
144
144
  set_value("enable_universal_constructor", "true" if enabled else "false")
145
145
 
146
146
 
147
+ def get_enable_streaming() -> bool:
148
+ """
149
+ Get the enable_streaming configuration value.
150
+ Controls whether streaming (SSE) is used for model responses.
151
+ Returns True if streaming is enabled, False otherwise.
152
+ Defaults to True.
153
+ """
154
+ val = get_value("enable_streaming")
155
+ if val is None:
156
+ return True # Default to True for better UX
157
+ return str(val).lower() in ("1", "true", "yes", "on")
158
+
159
+
147
160
  DEFAULT_SECTION = "puppy"
148
161
  REQUIRED_KEYS = ["puppy_name", "owner_name"]
149
162
 
@@ -289,6 +302,8 @@ def get_config_keys():
289
302
  default_keys.append("enable_pack_agents")
290
303
  # Add universal constructor control key
291
304
  default_keys.append("enable_universal_constructor")
305
+ # Add streaming control key
306
+ default_keys.append("enable_streaming")
292
307
  # Add cancel agent key configuration
293
308
  default_keys.append("cancel_agent_key")
294
309
  # Add banner color keys
@@ -102,17 +102,24 @@ class RetryingAsyncClient(httpx.AsyncClient):
102
102
 
103
103
  This replaces the Tenacity transport with a more direct subclass implementation,
104
104
  which plays nicer with proxies and custom transports (like Antigravity).
105
+
106
+ Special handling for Cerebras: Their Retry-After headers are absurdly aggressive
107
+ (often 60s), so we ignore them and use a 3s base backoff instead.
105
108
  """
106
109
 
107
110
  def __init__(
108
111
  self,
109
112
  retry_status_codes: tuple = (429, 502, 503, 504),
110
113
  max_retries: int = 5,
114
+ model_name: str = "",
111
115
  **kwargs,
112
116
  ):
113
117
  super().__init__(**kwargs)
114
118
  self.retry_status_codes = retry_status_codes
115
119
  self.max_retries = max_retries
120
+ self.model_name = model_name.lower() if model_name else ""
121
+ # Cerebras sends crazy aggressive Retry-After headers (60s), ignore them
122
+ self._ignore_retry_headers = "cerebras" in self.model_name
116
123
 
117
124
  async def send(self, request: httpx.Request, **kwargs: Any) -> httpx.Response:
118
125
  """Send request with automatic retries for rate limits and server errors."""
@@ -131,32 +138,39 @@ class RetryingAsyncClient(httpx.AsyncClient):
131
138
  # Close response if we're going to retry
132
139
  await response.aclose()
133
140
 
134
- # Determine wait time
135
- wait_time = 1.0 * (
136
- 2**attempt
137
- ) # Default exponential backoff: 1s, 2s, 4s...
138
-
139
- # Check Retry-After header
140
- retry_after = response.headers.get("Retry-After")
141
- if retry_after:
142
- try:
143
- wait_time = float(retry_after)
144
- except ValueError:
145
- # Try parsing http-date
146
- from email.utils import parsedate_to_datetime
141
+ # Determine wait time - Cerebras gets special treatment
142
+ if self._ignore_retry_headers:
143
+ # Cerebras: 3s base with exponential backoff (3s, 6s, 12s...)
144
+ wait_time = 3.0 * (2**attempt)
145
+ else:
146
+ # Default exponential backoff: 1s, 2s, 4s...
147
+ wait_time = 1.0 * (2**attempt)
147
148
 
149
+ # Check Retry-After header (only for non-Cerebras)
150
+ retry_after = response.headers.get("Retry-After")
151
+ if retry_after:
148
152
  try:
149
- date = parsedate_to_datetime(retry_after)
150
- wait_time = date.timestamp() - time.time()
151
- except Exception:
152
- pass
153
+ wait_time = float(retry_after)
154
+ except ValueError:
155
+ # Try parsing http-date
156
+ from email.utils import parsedate_to_datetime
157
+
158
+ try:
159
+ date = parsedate_to_datetime(retry_after)
160
+ wait_time = date.timestamp() - time.time()
161
+ except Exception:
162
+ pass
153
163
 
154
164
  # Cap wait time
155
165
  wait_time = max(0.5, min(wait_time, 60.0))
156
166
 
157
167
  if attempt < self.max_retries:
168
+ provider_note = (
169
+ " (ignoring header)" if self._ignore_retry_headers else ""
170
+ )
158
171
  emit_info(
159
- f"HTTP retry: {response.status_code} received. Waiting {wait_time:.1f}s (attempt {attempt + 1}/{self.max_retries})"
172
+ f"HTTP retry: {response.status_code} received{provider_note}. "
173
+ f"Waiting {wait_time:.1f}s (attempt {attempt + 1}/{self.max_retries})"
160
174
  )
161
175
  await asyncio.sleep(wait_time)
162
176
 
@@ -219,12 +233,14 @@ def create_async_client(
219
233
  verify: Union[bool, str] = None,
220
234
  headers: Optional[Dict[str, str]] = None,
221
235
  retry_status_codes: tuple = (429, 502, 503, 504),
236
+ model_name: str = "",
222
237
  ) -> httpx.AsyncClient:
223
238
  config = _resolve_proxy_config(verify)
224
239
 
225
240
  if not config.disable_retry:
226
241
  return RetryingAsyncClient(
227
242
  retry_status_codes=retry_status_codes,
243
+ model_name=model_name,
228
244
  proxy=config.proxy_url,
229
245
  verify=config.verify,
230
246
  headers=headers or {},
@@ -290,6 +306,7 @@ def create_reopenable_async_client(
290
306
  verify: Union[bool, str] = None,
291
307
  headers: Optional[Dict[str, str]] = None,
292
308
  retry_status_codes: tuple = (429, 502, 503, 504),
309
+ model_name: str = "",
293
310
  ) -> Union[ReopenableAsyncClient, httpx.AsyncClient]:
294
311
  config = _resolve_proxy_config(verify)
295
312
 
@@ -309,12 +326,15 @@ def create_reopenable_async_client(
309
326
  kwargs = {**base_kwargs, "client_class": client_class}
310
327
  if not config.disable_retry:
311
328
  kwargs["retry_status_codes"] = retry_status_codes
329
+ kwargs["model_name"] = model_name
312
330
  return ReopenableAsyncClient(**kwargs)
313
331
  else:
314
332
  # Fallback to RetryingAsyncClient or plain AsyncClient
315
333
  if not config.disable_retry:
316
334
  return RetryingAsyncClient(
317
- retry_status_codes=retry_status_codes, **base_kwargs
335
+ retry_status_codes=retry_status_codes,
336
+ model_name=model_name,
337
+ **base_kwargs,
318
338
  )
319
339
  else:
320
340
  return httpx.AsyncClient(**base_kwargs)
@@ -1025,7 +1025,20 @@ class MCPServerCatalog:
1025
1025
  """Catalog for searching and managing pre-configured MCP servers."""
1026
1026
 
1027
1027
  def __init__(self):
1028
- self.servers = MCP_SERVER_REGISTRY
1028
+ # Start with built-in servers
1029
+ self.servers = list(MCP_SERVER_REGISTRY)
1030
+
1031
+ # Let plugins add their own catalog entries
1032
+ try:
1033
+ from code_puppy.callbacks import on_register_mcp_catalog_servers
1034
+
1035
+ plugin_results = on_register_mcp_catalog_servers()
1036
+ for result in plugin_results:
1037
+ if isinstance(result, list):
1038
+ self.servers.extend(result)
1039
+ except Exception:
1040
+ pass # Don't break catalog if plugins fail
1041
+
1029
1042
  self._build_index()
1030
1043
 
1031
1044
  def _build_index(self):
@@ -585,7 +585,12 @@ class ModelFactory:
585
585
  return None
586
586
  # Add Cerebras 3rd party integration header
587
587
  headers["X-Cerebras-3rd-Party-Integration"] = "code-puppy"
588
- client = create_async_client(headers=headers, verify=verify)
588
+ # Pass "cerebras" so RetryingAsyncClient knows to ignore Cerebras's
589
+ # absurdly aggressive Retry-After headers (they send 60s!)
590
+ # Note: model_config["name"] is "zai-glm-4.7", not "cerebras"
591
+ client = create_async_client(
592
+ headers=headers, verify=verify, model_name="cerebras"
593
+ )
589
594
  provider_args = dict(
590
595
  api_key=api_key,
591
596
  http_client=client,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.378"
7
+ version = "0.0.380"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.14"
File without changes
File without changes
File without changes