code-puppy 0.0.908__tar.gz → 0.0.910__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 (326) hide show
  1. {code_puppy-0.0.908 → code_puppy-0.0.910}/PKG-INFO +1 -1
  2. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_builder.py +22 -2
  3. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/claude_cache_client.py +77 -40
  4. code_puppy-0.0.910/code_puppy/claude_thinking_display.py +71 -0
  5. {code_puppy-0.0.908 → code_puppy-0.0.910}/pyproject.toml +1 -1
  6. {code_puppy-0.0.908 → code_puppy-0.0.910}/.gitignore +0 -0
  7. {code_puppy-0.0.908 → code_puppy-0.0.910}/LICENSE +0 -0
  8. {code_puppy-0.0.908 → code_puppy-0.0.910}/README.md +0 -0
  9. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/__init__.py +0 -0
  10. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/__main__.py +0 -0
  11. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/_plugin_i18n_lifecycle.py +0 -0
  12. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/_pydantic_tool_helpers.py +0 -0
  13. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/_pydantic_video_patch.py +0 -0
  14. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agent_completion_inbox.py +0 -0
  15. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agent_execution_context.py +0 -0
  16. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/__init__.py +0 -0
  17. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_code_mode.py +0 -0
  18. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_code_mode_guidance.py +0 -0
  19. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_compaction.py +0 -0
  20. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_diagnostics.py +0 -0
  21. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_foreign_thinking.py +0 -0
  22. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_history.py +0 -0
  23. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_key_listeners.py +0 -0
  24. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_model_message_transform.py +0 -0
  25. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_non_streaming_render.py +0 -0
  26. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_output_limits.py +0 -0
  27. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_run_signals.py +0 -0
  28. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_runtime.py +0 -0
  29. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_steer_processor.py +0 -0
  30. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_subagent_recursion.py +0 -0
  31. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_windows_console.py +0 -0
  32. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/_wire_tool_names.py +0 -0
  33. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_code_puppy.py +0 -0
  34. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_creator_agent.py +0 -0
  35. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_helios.py +0 -0
  36. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_manager.py +0 -0
  37. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_model_judge.py +0 -0
  38. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_planning.py +0 -0
  39. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_qa_kitten.py +0 -0
  40. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/agent_web_retriever.py +0 -0
  41. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/base_agent.py +0 -0
  42. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/event_stream_handler.py +0 -0
  43. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/json_agent.py +0 -0
  44. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/retry_checkpoint.py +0 -0
  45. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/retry_profiles.py +0 -0
  46. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/run_stats.py +0 -0
  47. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/smooth_stream.py +0 -0
  48. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/stream_status.py +0 -0
  49. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/subagent_stream_handler.py +0 -0
  50. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/agents/thinking_output.py +0 -0
  51. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/asyncio_cleanup.py +0 -0
  52. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/atomic_io.py +0 -0
  53. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/atomic_json.py +0 -0
  54. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/ca_bundle.py +0 -0
  55. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/callbacks.py +0 -0
  56. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/capabilities/__init__.py +0 -0
  57. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/capabilities/compaction.py +0 -0
  58. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/capabilities/eager_timing.py +0 -0
  59. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/chatgpt_codex_client.py +0 -0
  60. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/claude_oauth_transport.py +0 -0
  61. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/cli_runner.py +0 -0
  62. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/__init__.py +0 -0
  63. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/add_model_details.py +0 -0
  64. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/add_model_menu.py +0 -0
  65. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/add_model_menus.py +0 -0
  66. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/add_model_vllm.py +0 -0
  67. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/agent_menu.py +0 -0
  68. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/attachments.py +0 -0
  69. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/autosave_menu.py +0 -0
  70. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/autosave_search.py +0 -0
  71. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/clipboard.py +0 -0
  72. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/colors_menu.py +0 -0
  73. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/command_handler.py +0 -0
  74. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/command_registry.py +0 -0
  75. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/completers.py +0 -0
  76. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/completion_cache.py +0 -0
  77. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/config_apply.py +0 -0
  78. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/config_commands.py +0 -0
  79. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/core_commands.py +0 -0
  80. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/file_index.py +0 -0
  81. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/file_path_completion.py +0 -0
  82. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/help_catalog.py +0 -0
  83. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/help_overlay.py +0 -0
  84. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/image_utils.py +0 -0
  85. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/load_context_completion.py +0 -0
  86. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/__init__.py +0 -0
  87. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/base.py +0 -0
  88. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
  89. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  90. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
  91. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/edit_command.py +0 -0
  92. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/handler.py +0 -0
  93. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/help_command.py +0 -0
  94. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/install_command.py +0 -0
  95. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/install_menu.py +0 -0
  96. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/list_command.py +0 -0
  97. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/logs_command.py +0 -0
  98. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/mcp_servers_store.py +0 -0
  99. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/remove_command.py +0 -0
  100. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/restart_command.py +0 -0
  101. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/search_command.py +0 -0
  102. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
  103. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  104. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/start_command.py +0 -0
  105. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/status_command.py +0 -0
  106. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  107. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/stop_command.py +0 -0
  108. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/trust_command.py +0 -0
  109. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/utils.py +0 -0
  110. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  111. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp_binding_menu.py +0 -0
  112. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/mcp_completion.py +0 -0
  113. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/menu_session.py +0 -0
  114. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/model_picker_completion.py +0 -0
  115. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/model_settings_defs.py +0 -0
  116. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/model_settings_menu.py +0 -0
  117. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/onboarding_slides.py +0 -0
  118. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/onboarding_wizard.py +0 -0
  119. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/pagination.py +0 -0
  120. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/pin_command_completion.py +0 -0
  121. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/refresh_models.py +0 -0
  122. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/session_browser.py +0 -0
  123. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/session_browser_data.py +0 -0
  124. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/session_commands.py +0 -0
  125. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/set_menu.py +0 -0
  126. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/set_menu_catalog.py +0 -0
  127. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/set_menu_schema.py +0 -0
  128. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/set_menu_settings.py +0 -0
  129. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/set_menu_shims.py +0 -0
  130. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/set_menu_values.py +0 -0
  131. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/shell_passthrough.py +0 -0
  132. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/skills_completion.py +0 -0
  133. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/tui_style.py +0 -0
  134. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/uc_menu.py +0 -0
  135. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/command_line/utils.py +0 -0
  136. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/config.py +0 -0
  137. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/config_file.py +0 -0
  138. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/diagnostics.py +0 -0
  139. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/error_logging.py +0 -0
  140. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/events/__init__.py +0 -0
  141. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/events/bridge.py +0 -0
  142. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/file_completion_io.py +0 -0
  143. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/file_completion_tokens.py +0 -0
  144. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/gemini_code_assist.py +0 -0
  145. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/gemini_common.py +0 -0
  146. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/gemini_model.py +0 -0
  147. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/README.md +0 -0
  148. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/__init__.py +0 -0
  149. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/aliases.py +0 -0
  150. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/engine.py +0 -0
  151. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/executor.py +0 -0
  152. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/matcher.py +0 -0
  153. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/models.py +0 -0
  154. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/registry.py +0 -0
  155. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/hook_engine/validator.py +0 -0
  156. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/http_retry.py +0 -0
  157. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/http_utils.py +0 -0
  158. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/httpx2_utils.py +0 -0
  159. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/__init__.py +0 -0
  160. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/audit.py +0 -0
  161. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/catalog.py +0 -0
  162. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/formats.py +0 -0
  163. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/interpolation.py +0 -0
  164. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/locale.py +0 -0
  165. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/locales/en-US.json +0 -0
  166. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/locales/es.json +0 -0
  167. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/locales/fr-CA.json +0 -0
  168. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/plugin_catalog.py +0 -0
  169. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/plurals.py +0 -0
  170. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/pseudo.py +0 -0
  171. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/i18n/translate.py +0 -0
  172. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/kennel_provider.py +0 -0
  173. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/keymap.py +0 -0
  174. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/list_filtering.py +0 -0
  175. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/main.py +0 -0
  176. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/__init__.py +0 -0
  177. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/agent_bindings.py +0 -0
  178. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/async_lifecycle.py +0 -0
  179. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/blocking_startup.py +0 -0
  180. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/circuit_breaker.py +0 -0
  181. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/config_wizard.py +0 -0
  182. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/dashboard.py +0 -0
  183. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/error_isolation.py +0 -0
  184. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/examples/retry_example.py +0 -0
  185. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/health_monitor.py +0 -0
  186. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/http_auth.py +0 -0
  187. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/managed_server.py +0 -0
  188. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/manager.py +0 -0
  189. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/manager_lifecycle.py +0 -0
  190. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/mcp_logs.py +0 -0
  191. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/project_config.py +0 -0
  192. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/registry.py +0 -0
  193. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/retry_manager.py +0 -0
  194. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/server_registry_catalog.py +0 -0
  195. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/status_tracker.py +0 -0
  196. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/system_tools.py +0 -0
  197. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/tool_arg_coercion.py +0 -0
  198. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_/toolset_utils.py +0 -0
  199. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_prompts/__init__.py +0 -0
  200. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/mcp_prompts/hook_creator.py +0 -0
  201. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/__init__.py +0 -0
  202. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/bar_painters.py +0 -0
  203. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/bar_rendering.py +0 -0
  204. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/bottom_bar.py +0 -0
  205. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/bus.py +0 -0
  206. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/chords.py +0 -0
  207. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/commands.py +0 -0
  208. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_actions.py +0 -0
  209. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_completion.py +0 -0
  210. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_display.py +0 -0
  211. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_history.py +0 -0
  212. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_keys.py +0 -0
  213. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_paste.py +0 -0
  214. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_queue.py +0 -0
  215. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/editor_submission.py +0 -0
  216. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/external_editor.py +0 -0
  217. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/identity_line.py +0 -0
  218. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/idle_status.py +0 -0
  219. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/inline_bar.py +0 -0
  220. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/line_editor.py +0 -0
  221. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/markdown_patches.py +0 -0
  222. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/menu_lifecycle.py +0 -0
  223. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/message_queue.py +0 -0
  224. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/messages.py +0 -0
  225. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/pause_controller.py +0 -0
  226. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/prompt_prefix_style.py +0 -0
  227. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/queue_console.py +0 -0
  228. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/renderers.py +0 -0
  229. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/rich_renderer.py +0 -0
  230. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/run_ui.py +0 -0
  231. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/run_ui_wiring.py +0 -0
  232. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/speculation_line.py +0 -0
  233. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/speculation_stats.py +0 -0
  234. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/speculation_toggle.py +0 -0
  235. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/spinner/__init__.py +0 -0
  236. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/status_line.py +0 -0
  237. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/subagent_console.py +0 -0
  238. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/theme_accent.py +0 -0
  239. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/tool_output.py +0 -0
  240. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/messaging/transcript_guard.py +0 -0
  241. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/model_descriptions.py +0 -0
  242. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/model_factory.py +0 -0
  243. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/model_switching.py +0 -0
  244. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/model_utils.py +0 -0
  245. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/models.json +0 -0
  246. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/models_dev_api.json +0 -0
  247. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/models_dev_parser.py +0 -0
  248. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/observability.py +0 -0
  249. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/platform_utils.py +0 -0
  250. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/plugins/__init__.py +0 -0
  251. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/plugins/config.py +0 -0
  252. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/plugins/oauth_pasteback.py +0 -0
  253. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/plugins/oauth_puppy_html.py +0 -0
  254. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/plugins/trust.py +0 -0
  255. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/plugins/trust_notice.py +0 -0
  256. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/private_inference.py +0 -0
  257. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/provider_credentials.py +0 -0
  258. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/provider_identity.py +0 -0
  259. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/pydantic_patches.py +0 -0
  260. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/reopenable_async_client.py +0 -0
  261. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/round_robin_model.py +0 -0
  262. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/secret_store.py +0 -0
  263. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/secret_store_backends.py +0 -0
  264. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/session_format_migration.py +0 -0
  265. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/session_lifecycle.py +0 -0
  266. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/session_migration.py +0 -0
  267. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/session_storage.py +0 -0
  268. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/session_surrogate_unpickler.py +0 -0
  269. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/shared_credentials.py +0 -0
  270. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/skill_provider.py +0 -0
  271. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/splash.py +0 -0
  272. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/status_display.py +0 -0
  273. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/steer_metadata.py +0 -0
  274. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/terminal_utils.py +0 -0
  275. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/token_usage.py +0 -0
  276. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/__init__.py +0 -0
  277. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/_browser_registry.py +0 -0
  278. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/_lazy.py +0 -0
  279. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/agent_tools.py +0 -0
  280. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/approval_feedback.py +0 -0
  281. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/__init__.py +0 -0
  282. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/constants.py +0 -0
  283. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
  284. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/handler.py +0 -0
  285. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/models.py +0 -0
  286. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/registration.py +0 -0
  287. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/renderers.py +0 -0
  288. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
  289. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/theme.py +0 -0
  290. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
  291. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/__init__.py +0 -0
  292. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_control.py +0 -0
  293. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_interactions.py +0 -0
  294. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_locator_resolver.py +0 -0
  295. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_locators.py +0 -0
  296. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_manager.py +0 -0
  297. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_navigation.py +0 -0
  298. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_page_snapshot.py +0 -0
  299. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  300. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_scripts.py +0 -0
  301. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_semantic_interactions.py +0 -0
  302. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/browser_workflows.py +0 -0
  303. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/browser/tool_registry.py +0 -0
  304. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/command_runner.py +0 -0
  305. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/common.py +0 -0
  306. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/display.py +0 -0
  307. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/file_modifications.py +0 -0
  308. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/file_operations.py +0 -0
  309. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/file_permission_state.py +0 -0
  310. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/fs_access.py +0 -0
  311. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/image_tools.py +0 -0
  312. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/io_backends.py +0 -0
  313. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/model_tools.py +0 -0
  314. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/ripgrep.py +0 -0
  315. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/shell_backgrounding.py +0 -0
  316. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/skills_tools.py +0 -0
  317. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/subagent_context.py +0 -0
  318. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/subagent_invocation.py +0 -0
  319. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/subagent_usage_metrics.py +0 -0
  320. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/tools_content.py +0 -0
  321. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/universal_constructor.py +0 -0
  322. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/tools/win_shell_io.py +0 -0
  323. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/undo_manager.py +0 -0
  324. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/universal_constructor_provider.py +0 -0
  325. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/version_checker.py +0 -0
  326. {code_puppy-0.0.908 → code_puppy-0.0.910}/code_puppy/zai_model.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: code-puppy
3
- Version: 0.0.908
3
+ Version: 0.0.910
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
@@ -11,6 +11,7 @@ hook; see :func:`code_puppy.callbacks.on_wrap_pydantic_agent`.
11
11
 
12
12
  from __future__ import annotations
13
13
 
14
+ import os
14
15
  import uuid
15
16
  from pathlib import Path
16
17
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple
@@ -142,6 +143,23 @@ def _truncate_agents_md(content: str, source: str, max_chars: int) -> str:
142
143
  return content[:max_chars] + notice
143
144
 
144
145
 
146
+ def _same_file(candidate: Path, other: Optional[Path]) -> bool:
147
+ """True when ``candidate`` is the very file ``other`` names.
148
+
149
+ Run from the home directory, ``.code_puppy/AGENTS.md`` *is* the global
150
+ ``~/.code_puppy/AGENTS.md``; loading it again as project rules puts the
151
+ same text into the system prompt twice. Compared by filesystem identity,
152
+ so symlinks and path aliases count as the same file, while a distinct
153
+ project file with identical text still loads.
154
+ """
155
+ if other is None:
156
+ return False
157
+ try:
158
+ return os.path.samefile(candidate, other)
159
+ except OSError:
160
+ return False
161
+
162
+
145
163
  def load_puppy_rules() -> Optional[str]:
146
164
  """Load AGENT(S).md from global config dir and/or the current project dir.
147
165
 
@@ -163,12 +181,14 @@ def load_puppy_rules() -> Optional[str]:
163
181
  max_chars = get_agents_md_max_chars()
164
182
 
165
183
  global_rules: Optional[str] = None
184
+ global_file: Optional[Path] = None
166
185
  for name in _AGENT_RULE_FILES:
167
186
  candidate = Path(CONFIG_DIR) / name
168
187
  if candidate.exists():
169
188
  text = _read_rules_text(candidate)
170
189
  if text is None:
171
190
  continue
191
+ global_file = candidate
172
192
  global_rules = _truncate_agents_md(
173
193
  text,
174
194
  source=f"global {_friendly_path(candidate)}",
@@ -183,7 +203,7 @@ def load_puppy_rules() -> Optional[str]:
183
203
  if code_puppy_dir.is_dir():
184
204
  for name in _AGENT_RULE_FILES:
185
205
  candidate = code_puppy_dir / name
186
- if candidate.exists():
206
+ if candidate.exists() and not _same_file(candidate, global_file):
187
207
  text = _read_rules_text(candidate)
188
208
  if text is None:
189
209
  continue
@@ -198,7 +218,7 @@ def load_puppy_rules() -> Optional[str]:
198
218
  if project_rules is None:
199
219
  for name in _AGENT_RULE_FILES:
200
220
  candidate = Path(name)
201
- if candidate.exists():
221
+ if candidate.exists() and not _same_file(candidate, global_file):
202
222
  text = _read_rules_text(candidate)
203
223
  if text is None:
204
224
  continue
@@ -24,6 +24,12 @@ from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
24
24
  import httpx2
25
25
 
26
26
  from .claude_oauth_transport import ClaudeOAuthTransport
27
+ from .claude_thinking_display import (
28
+ _OFF_THINKING_TYPES,
29
+ _THINKING_OMITTED_WHEN_OFF,
30
+ _enforce_thinking_display_summary,
31
+ _thinking_endpoint,
32
+ )
27
33
  from .http_retry import describe_exception
28
34
 
29
35
  logger = logging.getLogger(__name__)
@@ -51,41 +57,6 @@ CLAUDE_CODE_SYSTEM_PROMPT = "You are Claude Code, Anthropic's official CLI for C
51
57
  THINKING_DISPLAY_UPDATES_BETA = "thinking-display-updates-2026-08-18"
52
58
 
53
59
 
54
- def _model_requires_thinking_summary(model_name):
55
- if not model_name:
56
- return False
57
- from code_puppy.model_utils import should_use_anthropic_thinking_summary
58
-
59
- return should_use_anthropic_thinking_summary(model_name)
60
-
61
-
62
- def _model_supports_thinking_updates(model_name):
63
- if not model_name:
64
- return False
65
- from code_puppy.model_utils import should_use_anthropic_thinking_updates
66
-
67
- return should_use_anthropic_thinking_updates(model_name)
68
-
69
-
70
- def _enforce_thinking_display_summary(payload):
71
- if not isinstance(payload, dict):
72
- return False
73
- if not _model_requires_thinking_summary(payload.get("model")):
74
- return False
75
- thinking = payload.get("thinking")
76
- if not isinstance(thinking, dict):
77
- return False
78
- display = thinking.get("display")
79
- if display == "summarized":
80
- return False
81
- if display == "updates" and _model_supports_thinking_updates(payload.get("model")):
82
- # Fable 5.1 legitimately asked for progress updates; don't clobber
83
- # it back to summarized (which would drown status lines in reasoning).
84
- return False
85
- thinking["display"] = "summarized"
86
- return True
87
-
88
-
89
60
  class ClaudeCacheAsyncClient(ClaudeOAuthTransport, httpx2.AsyncClient):
90
61
  """Async HTTP client with Claude Code OAuth transformations.
91
62
 
@@ -196,14 +167,16 @@ class ClaudeCacheAsyncClient(ClaudeOAuthTransport, httpx2.AsyncClient):
196
167
  return json.dumps(data).encode("utf-8")
197
168
 
198
169
  @staticmethod
199
- def _enforce_thinking_display_summary_body(body: bytes) -> bytes | None:
200
- """Return a rewritten body when summarized thinking is required."""
170
+ def _enforce_thinking_display_summary_body(
171
+ body: bytes, endpoint=None
172
+ ) -> bytes | None:
173
+ """Return a rewritten body when the thinking shape needs normalizing."""
201
174
  try:
202
175
  payload = json.loads(body.decode("utf-8"))
203
176
  except Exception:
204
177
  return None
205
178
  if not isinstance(payload, dict) or not _enforce_thinking_display_summary(
206
- payload
179
+ payload, endpoint
207
180
  ):
208
181
  return None
209
182
  return json.dumps(payload).encode("utf-8")
@@ -318,7 +291,7 @@ class ClaudeCacheAsyncClient(ClaudeOAuthTransport, httpx2.AsyncClient):
318
291
  body_modified = True
319
292
  if body_bytes:
320
293
  summarized_body = self._enforce_thinking_display_summary_body(
321
- body_bytes
294
+ body_bytes, _thinking_endpoint(url)
322
295
  )
323
296
  if summarized_body is not None:
324
297
  body_bytes = summarized_body
@@ -354,6 +327,10 @@ class ClaudeCacheAsyncClient(ClaudeOAuthTransport, httpx2.AsyncClient):
354
327
  except Exception as exc:
355
328
  logger.debug("Error in Claude Code transformations: %s", exc)
356
329
  response = await self._send_with_retries(request, *args, **kwargs)
330
+ if is_messages_endpoint:
331
+ request, response = await self._retry_without_thinking_after_400(
332
+ request, response, *args, **kwargs
333
+ )
357
334
  try:
358
335
  if (
359
336
  oauth_request
@@ -389,9 +366,14 @@ class ClaudeCacheAsyncClient(ClaudeOAuthTransport, httpx2.AsyncClient):
389
366
  retry_request.extensions["claude_oauth_refresh_attempted"] = (
390
367
  True
391
368
  )
392
- return await self._send_with_retries(
369
+ retried = await self._send_with_retries(
393
370
  retry_request, *args, **kwargs
394
371
  )
372
+ if is_messages_endpoint:
373
+ _, retried = await self._retry_without_thinking_after_400(
374
+ retry_request, retried, *args, **kwargs
375
+ )
376
+ return retried
395
377
  else:
396
378
  logger.warning(
397
379
  "Token recovery failed, returning original error"
@@ -400,6 +382,61 @@ class ClaudeCacheAsyncClient(ClaudeOAuthTransport, httpx2.AsyncClient):
400
382
  logger.debug("Error during token refresh attempt: %s", exc)
401
383
  return response
402
384
 
385
+ async def _retry_without_thinking_after_400(
386
+ self,
387
+ request: httpx2.Request,
388
+ response: httpx2.Response,
389
+ *args: Any,
390
+ **kwargs: Any,
391
+ ) -> tuple[httpx2.Request, httpx2.Response]:
392
+ """Resend once without ``thinking`` when the API refuses the off-switch.
393
+
394
+ Which "thinking off" shape a model accepts differs per model and
395
+ changes over time, so ask the API instead of keeping a list: a 400
396
+ that names ``thinking`` on a request that only asked for thinking
397
+ off is retried with the key omitted, which every probed model
398
+ accepts. The (endpoint, model) is remembered only once that retry
399
+ succeeds. Returns the request actually in effect so OAuth recovery
400
+ resends the corrected body, not the refused one.
401
+ """
402
+ if response.status_code != 400:
403
+ return request, response
404
+ try:
405
+ body = self._extract_body_bytes(request)
406
+ payload = json.loads(body) if body else None
407
+ thinking = payload.get("thinking") if isinstance(payload, dict) else None
408
+ if not isinstance(thinking, dict) or (
409
+ thinking.get("type") not in _OFF_THINKING_TYPES
410
+ ):
411
+ return request, response
412
+ error = json.loads(await response.aread()).get("error") or {}
413
+ if "thinking" not in str(error.get("message", "")).lower():
414
+ return request, response
415
+ del payload["thinking"]
416
+ headers = {
417
+ k: v
418
+ for k, v in request.headers.items()
419
+ if k.lower() != "content-length"
420
+ }
421
+ retry_request = self.build_request(
422
+ method=request.method,
423
+ url=request.url,
424
+ headers=headers,
425
+ content=json.dumps(payload).encode("utf-8"),
426
+ extensions=dict(request.extensions),
427
+ )
428
+ except Exception as exc:
429
+ logger.debug("Could not retry without thinking: %s", exc)
430
+ return request, response
431
+ logger.info("Model refused thinking off-switch; retrying without thinking")
432
+ await response.aclose()
433
+ retried = await self._send_with_retries(retry_request, *args, **kwargs)
434
+ if retried.status_code < 400:
435
+ _THINKING_OMITTED_WHEN_OFF.add(
436
+ (_thinking_endpoint(request.url), payload.get("model"))
437
+ )
438
+ return retry_request, retried
439
+
403
440
  async def _send_with_retries(
404
441
  self, request: httpx2.Request, *args: Any, **kwargs: Any
405
442
  ) -> httpx2.Response:
@@ -0,0 +1,71 @@
1
+ """Thinking ``display`` / off-switch normalization for Anthropic request bodies.
2
+
3
+ The API only accepts ``display`` while thinking runs (``adaptive`` /
4
+ ``enabled``). Which "thinking off" shape a model accepts differs per model, so
5
+ nothing here names a model: the client learns it from the provider's own 400.
6
+
7
+ Called by: claude_cache_client :: ClaudeCacheAsyncClient.send()
8
+ """
9
+
10
+
11
+ def _model_requires_thinking_summary(model_name):
12
+ if not model_name:
13
+ return False
14
+ from code_puppy.model_utils import should_use_anthropic_thinking_summary
15
+
16
+ return should_use_anthropic_thinking_summary(model_name)
17
+
18
+
19
+ def _model_supports_thinking_updates(model_name):
20
+ if not model_name:
21
+ return False
22
+ from code_puppy.model_utils import should_use_anthropic_thinking_updates
23
+
24
+ return should_use_anthropic_thinking_updates(model_name)
25
+
26
+
27
+ # The API only accepts ``thinking.display`` while thinking actually runs.
28
+ _DISPLAY_THINKING_TYPES = frozenset({"adaptive", "enabled"})
29
+ _OFF_THINKING_TYPES = frozenset({"disabled", "between_tools"})
30
+
31
+ # (endpoint, model) pairs whose API refused an "off" thinking shape and then
32
+ # accepted the request without it (see ``_retry_without_thinking_after_400``).
33
+ # Never listed by name: each family accepts a different off-switch, and the
34
+ # same model ID can sit behind providers that disagree, hence the endpoint.
35
+ _THINKING_OMITTED_WHEN_OFF: set[tuple] = set()
36
+
37
+
38
+ def _thinking_endpoint(url):
39
+ return (url.host, url.port, url.path)
40
+
41
+
42
+ def _normalize_thinking_off(payload, thinking, endpoint):
43
+ modified = thinking.pop("display", None) is not None
44
+ if (
45
+ thinking.get("type") in _OFF_THINKING_TYPES
46
+ and (endpoint, payload.get("model")) in _THINKING_OMITTED_WHEN_OFF
47
+ ):
48
+ del payload["thinking"]
49
+ return True
50
+ return modified
51
+
52
+
53
+ def _enforce_thinking_display_summary(payload, endpoint=None):
54
+ if not isinstance(payload, dict):
55
+ return False
56
+ thinking = payload.get("thinking")
57
+ if not isinstance(thinking, dict):
58
+ return False
59
+ if thinking.get("type") not in _DISPLAY_THINKING_TYPES:
60
+ return _normalize_thinking_off(payload, thinking, endpoint)
61
+ if not _model_requires_thinking_summary(payload.get("model")):
62
+ return False
63
+ display = thinking.get("display")
64
+ if display == "summarized":
65
+ return False
66
+ if display == "updates" and _model_supports_thinking_updates(payload.get("model")):
67
+ # Fable 5.1 legitimately asked for progress updates; don't clobber
68
+ # it back to summarized (which would drown status lines in reasoning).
69
+ return False
70
+ thinking["display"] = "summarized"
71
+ return True
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.908"
7
+ version = "0.0.910"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.15"
File without changes
File without changes
File without changes