newcode 0.1.1__py3-none-any.whl

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 (289) hide show
  1. code_puppy/__init__.py +10 -0
  2. code_puppy/__main__.py +10 -0
  3. code_puppy/agents/__init__.py +31 -0
  4. code_puppy/agents/agent_c_reviewer.py +155 -0
  5. code_puppy/agents/agent_code_puppy.py +147 -0
  6. code_puppy/agents/agent_code_reviewer.py +90 -0
  7. code_puppy/agents/agent_cpp_reviewer.py +132 -0
  8. code_puppy/agents/agent_creator_agent.py +630 -0
  9. code_puppy/agents/agent_golang_reviewer.py +151 -0
  10. code_puppy/agents/agent_helios.py +122 -0
  11. code_puppy/agents/agent_javascript_reviewer.py +160 -0
  12. code_puppy/agents/agent_manager.py +742 -0
  13. code_puppy/agents/agent_pack_leader.py +380 -0
  14. code_puppy/agents/agent_planning.py +165 -0
  15. code_puppy/agents/agent_python_programmer.py +167 -0
  16. code_puppy/agents/agent_python_reviewer.py +90 -0
  17. code_puppy/agents/agent_qa_expert.py +163 -0
  18. code_puppy/agents/agent_qa_kitten.py +208 -0
  19. code_puppy/agents/agent_scheduler.py +121 -0
  20. code_puppy/agents/agent_security_auditor.py +181 -0
  21. code_puppy/agents/agent_terminal_qa.py +323 -0
  22. code_puppy/agents/agent_typescript_reviewer.py +166 -0
  23. code_puppy/agents/base_agent.py +2145 -0
  24. code_puppy/agents/event_stream_handler.py +348 -0
  25. code_puppy/agents/json_agent.py +202 -0
  26. code_puppy/agents/pack/__init__.py +34 -0
  27. code_puppy/agents/pack/bloodhound.py +296 -0
  28. code_puppy/agents/pack/husky.py +307 -0
  29. code_puppy/agents/pack/retriever.py +380 -0
  30. code_puppy/agents/pack/shepherd.py +327 -0
  31. code_puppy/agents/pack/terrier.py +281 -0
  32. code_puppy/agents/pack/watchdog.py +357 -0
  33. code_puppy/agents/prompt_reviewer.py +145 -0
  34. code_puppy/agents/subagent_stream_handler.py +276 -0
  35. code_puppy/api/__init__.py +13 -0
  36. code_puppy/api/app.py +169 -0
  37. code_puppy/api/main.py +21 -0
  38. code_puppy/api/pty_manager.py +453 -0
  39. code_puppy/api/routers/__init__.py +12 -0
  40. code_puppy/api/routers/agents.py +36 -0
  41. code_puppy/api/routers/commands.py +217 -0
  42. code_puppy/api/routers/config.py +75 -0
  43. code_puppy/api/routers/sessions.py +234 -0
  44. code_puppy/api/templates/terminal.html +361 -0
  45. code_puppy/api/websocket.py +154 -0
  46. code_puppy/callbacks.py +674 -0
  47. code_puppy/chatgpt_codex_client.py +338 -0
  48. code_puppy/claude_cache_client.py +664 -0
  49. code_puppy/cli_runner.py +1038 -0
  50. code_puppy/command_line/__init__.py +1 -0
  51. code_puppy/command_line/add_model_menu.py +1092 -0
  52. code_puppy/command_line/agent_menu.py +662 -0
  53. code_puppy/command_line/attachments.py +395 -0
  54. code_puppy/command_line/autosave_menu.py +704 -0
  55. code_puppy/command_line/clipboard.py +527 -0
  56. code_puppy/command_line/colors_menu.py +526 -0
  57. code_puppy/command_line/command_handler.py +283 -0
  58. code_puppy/command_line/command_registry.py +150 -0
  59. code_puppy/command_line/config_commands.py +719 -0
  60. code_puppy/command_line/core_commands.py +853 -0
  61. code_puppy/command_line/diff_menu.py +865 -0
  62. code_puppy/command_line/file_path_completion.py +73 -0
  63. code_puppy/command_line/load_context_completion.py +52 -0
  64. code_puppy/command_line/mcp/__init__.py +10 -0
  65. code_puppy/command_line/mcp/base.py +32 -0
  66. code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
  67. code_puppy/command_line/mcp/custom_server_form.py +688 -0
  68. code_puppy/command_line/mcp/custom_server_installer.py +195 -0
  69. code_puppy/command_line/mcp/edit_command.py +148 -0
  70. code_puppy/command_line/mcp/handler.py +138 -0
  71. code_puppy/command_line/mcp/help_command.py +147 -0
  72. code_puppy/command_line/mcp/install_command.py +214 -0
  73. code_puppy/command_line/mcp/install_menu.py +705 -0
  74. code_puppy/command_line/mcp/list_command.py +94 -0
  75. code_puppy/command_line/mcp/logs_command.py +235 -0
  76. code_puppy/command_line/mcp/remove_command.py +82 -0
  77. code_puppy/command_line/mcp/restart_command.py +100 -0
  78. code_puppy/command_line/mcp/search_command.py +123 -0
  79. code_puppy/command_line/mcp/start_all_command.py +135 -0
  80. code_puppy/command_line/mcp/start_command.py +117 -0
  81. code_puppy/command_line/mcp/status_command.py +184 -0
  82. code_puppy/command_line/mcp/stop_all_command.py +112 -0
  83. code_puppy/command_line/mcp/stop_command.py +80 -0
  84. code_puppy/command_line/mcp/test_command.py +107 -0
  85. code_puppy/command_line/mcp/utils.py +129 -0
  86. code_puppy/command_line/mcp/wizard_utils.py +334 -0
  87. code_puppy/command_line/mcp_completion.py +174 -0
  88. code_puppy/command_line/model_picker_completion.py +197 -0
  89. code_puppy/command_line/model_settings_menu.py +932 -0
  90. code_puppy/command_line/motd.py +91 -0
  91. code_puppy/command_line/onboarding_slides.py +179 -0
  92. code_puppy/command_line/onboarding_wizard.py +342 -0
  93. code_puppy/command_line/pin_command_completion.py +329 -0
  94. code_puppy/command_line/prompt_toolkit_completion.py +846 -0
  95. code_puppy/command_line/session_commands.py +302 -0
  96. code_puppy/command_line/skills_completion.py +160 -0
  97. code_puppy/command_line/uc_menu.py +893 -0
  98. code_puppy/command_line/utils.py +93 -0
  99. code_puppy/command_line/wiggum_state.py +78 -0
  100. code_puppy/config.py +1787 -0
  101. code_puppy/error_logging.py +133 -0
  102. code_puppy/gemini_code_assist.py +385 -0
  103. code_puppy/gemini_model.py +754 -0
  104. code_puppy/hook_engine/README.md +105 -0
  105. code_puppy/hook_engine/__init__.py +15 -0
  106. code_puppy/hook_engine/aliases.py +155 -0
  107. code_puppy/hook_engine/engine.py +195 -0
  108. code_puppy/hook_engine/executor.py +293 -0
  109. code_puppy/hook_engine/matcher.py +145 -0
  110. code_puppy/hook_engine/models.py +222 -0
  111. code_puppy/hook_engine/registry.py +106 -0
  112. code_puppy/hook_engine/validator.py +141 -0
  113. code_puppy/http_utils.py +361 -0
  114. code_puppy/keymap.py +128 -0
  115. code_puppy/main.py +10 -0
  116. code_puppy/mcp_/__init__.py +66 -0
  117. code_puppy/mcp_/async_lifecycle.py +286 -0
  118. code_puppy/mcp_/blocking_startup.py +469 -0
  119. code_puppy/mcp_/captured_stdio_server.py +275 -0
  120. code_puppy/mcp_/circuit_breaker.py +290 -0
  121. code_puppy/mcp_/config_wizard.py +507 -0
  122. code_puppy/mcp_/dashboard.py +308 -0
  123. code_puppy/mcp_/error_isolation.py +407 -0
  124. code_puppy/mcp_/examples/retry_example.py +226 -0
  125. code_puppy/mcp_/health_monitor.py +589 -0
  126. code_puppy/mcp_/managed_server.py +428 -0
  127. code_puppy/mcp_/manager.py +807 -0
  128. code_puppy/mcp_/mcp_logs.py +224 -0
  129. code_puppy/mcp_/registry.py +451 -0
  130. code_puppy/mcp_/retry_manager.py +337 -0
  131. code_puppy/mcp_/server_registry_catalog.py +1126 -0
  132. code_puppy/mcp_/status_tracker.py +355 -0
  133. code_puppy/mcp_/system_tools.py +209 -0
  134. code_puppy/mcp_prompts/__init__.py +1 -0
  135. code_puppy/mcp_prompts/hook_creator.py +103 -0
  136. code_puppy/messaging/__init__.py +255 -0
  137. code_puppy/messaging/bus.py +613 -0
  138. code_puppy/messaging/commands.py +167 -0
  139. code_puppy/messaging/markdown_patches.py +57 -0
  140. code_puppy/messaging/message_queue.py +361 -0
  141. code_puppy/messaging/messages.py +569 -0
  142. code_puppy/messaging/queue_console.py +271 -0
  143. code_puppy/messaging/renderers.py +311 -0
  144. code_puppy/messaging/rich_renderer.py +1153 -0
  145. code_puppy/messaging/spinner/__init__.py +83 -0
  146. code_puppy/messaging/spinner/console_spinner.py +240 -0
  147. code_puppy/messaging/spinner/spinner_base.py +96 -0
  148. code_puppy/messaging/subagent_console.py +460 -0
  149. code_puppy/model_factory.py +848 -0
  150. code_puppy/model_switching.py +63 -0
  151. code_puppy/model_utils.py +168 -0
  152. code_puppy/models.json +130 -0
  153. code_puppy/models_dev_api.json +1 -0
  154. code_puppy/models_dev_parser.py +592 -0
  155. code_puppy/plugins/__init__.py +186 -0
  156. code_puppy/plugins/agent_skills/__init__.py +22 -0
  157. code_puppy/plugins/agent_skills/config.py +175 -0
  158. code_puppy/plugins/agent_skills/discovery.py +136 -0
  159. code_puppy/plugins/agent_skills/downloader.py +392 -0
  160. code_puppy/plugins/agent_skills/installer.py +22 -0
  161. code_puppy/plugins/agent_skills/metadata.py +219 -0
  162. code_puppy/plugins/agent_skills/prompt_builder.py +100 -0
  163. code_puppy/plugins/agent_skills/register_callbacks.py +241 -0
  164. code_puppy/plugins/agent_skills/remote_catalog.py +322 -0
  165. code_puppy/plugins/agent_skills/skill_catalog.py +257 -0
  166. code_puppy/plugins/agent_skills/skills_install_menu.py +664 -0
  167. code_puppy/plugins/agent_skills/skills_menu.py +781 -0
  168. code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
  169. code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
  170. code_puppy/plugins/antigravity_oauth/antigravity_model.py +706 -0
  171. code_puppy/plugins/antigravity_oauth/config.py +42 -0
  172. code_puppy/plugins/antigravity_oauth/constants.py +133 -0
  173. code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
  174. code_puppy/plugins/antigravity_oauth/register_callbacks.py +518 -0
  175. code_puppy/plugins/antigravity_oauth/storage.py +288 -0
  176. code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
  177. code_puppy/plugins/antigravity_oauth/token.py +167 -0
  178. code_puppy/plugins/antigravity_oauth/transport.py +863 -0
  179. code_puppy/plugins/antigravity_oauth/utils.py +168 -0
  180. code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
  181. code_puppy/plugins/chatgpt_oauth/config.py +52 -0
  182. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +328 -0
  183. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +176 -0
  184. code_puppy/plugins/chatgpt_oauth/test_plugin.py +295 -0
  185. code_puppy/plugins/chatgpt_oauth/utils.py +499 -0
  186. code_puppy/plugins/claude_code_hooks/__init__.py +1 -0
  187. code_puppy/plugins/claude_code_hooks/config.py +131 -0
  188. code_puppy/plugins/claude_code_hooks/register_callbacks.py +163 -0
  189. code_puppy/plugins/claude_code_oauth/README.md +167 -0
  190. code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
  191. code_puppy/plugins/claude_code_oauth/__init__.py +25 -0
  192. code_puppy/plugins/claude_code_oauth/config.py +52 -0
  193. code_puppy/plugins/claude_code_oauth/register_callbacks.py +453 -0
  194. code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
  195. code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +241 -0
  196. code_puppy/plugins/claude_code_oauth/utils.py +601 -0
  197. code_puppy/plugins/customizable_commands/__init__.py +0 -0
  198. code_puppy/plugins/customizable_commands/register_callbacks.py +152 -0
  199. code_puppy/plugins/example_custom_command/README.md +280 -0
  200. code_puppy/plugins/example_custom_command/register_callbacks.py +48 -0
  201. code_puppy/plugins/file_permission_handler/__init__.py +4 -0
  202. code_puppy/plugins/file_permission_handler/register_callbacks.py +528 -0
  203. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  204. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  205. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  206. code_puppy/plugins/hook_creator/__init__.py +1 -0
  207. code_puppy/plugins/hook_creator/register_callbacks.py +33 -0
  208. code_puppy/plugins/hook_manager/__init__.py +1 -0
  209. code_puppy/plugins/hook_manager/config.py +277 -0
  210. code_puppy/plugins/hook_manager/hooks_menu.py +551 -0
  211. code_puppy/plugins/hook_manager/register_callbacks.py +205 -0
  212. code_puppy/plugins/oauth_puppy_html.py +224 -0
  213. code_puppy/plugins/scheduler/__init__.py +1 -0
  214. code_puppy/plugins/scheduler/register_callbacks.py +88 -0
  215. code_puppy/plugins/scheduler/scheduler_menu.py +522 -0
  216. code_puppy/plugins/scheduler/scheduler_wizard.py +341 -0
  217. code_puppy/plugins/shell_safety/__init__.py +6 -0
  218. code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
  219. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  220. code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
  221. code_puppy/plugins/synthetic_status/__init__.py +1 -0
  222. code_puppy/plugins/synthetic_status/register_callbacks.py +132 -0
  223. code_puppy/plugins/synthetic_status/status_api.py +147 -0
  224. code_puppy/plugins/universal_constructor/__init__.py +13 -0
  225. code_puppy/plugins/universal_constructor/models.py +138 -0
  226. code_puppy/plugins/universal_constructor/register_callbacks.py +47 -0
  227. code_puppy/plugins/universal_constructor/registry.py +302 -0
  228. code_puppy/plugins/universal_constructor/sandbox.py +584 -0
  229. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  230. code_puppy/pydantic_patches.py +317 -0
  231. code_puppy/reopenable_async_client.py +232 -0
  232. code_puppy/round_robin_model.py +150 -0
  233. code_puppy/scheduler/__init__.py +41 -0
  234. code_puppy/scheduler/__main__.py +9 -0
  235. code_puppy/scheduler/cli.py +118 -0
  236. code_puppy/scheduler/config.py +126 -0
  237. code_puppy/scheduler/daemon.py +280 -0
  238. code_puppy/scheduler/executor.py +155 -0
  239. code_puppy/scheduler/platform.py +19 -0
  240. code_puppy/scheduler/platform_unix.py +22 -0
  241. code_puppy/scheduler/platform_win.py +32 -0
  242. code_puppy/session_storage.py +338 -0
  243. code_puppy/status_display.py +257 -0
  244. code_puppy/summarization_agent.py +176 -0
  245. code_puppy/terminal_utils.py +418 -0
  246. code_puppy/tools/__init__.py +470 -0
  247. code_puppy/tools/agent_tools.py +616 -0
  248. code_puppy/tools/ask_user_question/__init__.py +26 -0
  249. code_puppy/tools/ask_user_question/constants.py +73 -0
  250. code_puppy/tools/ask_user_question/demo_tui.py +55 -0
  251. code_puppy/tools/ask_user_question/handler.py +232 -0
  252. code_puppy/tools/ask_user_question/models.py +304 -0
  253. code_puppy/tools/ask_user_question/registration.py +36 -0
  254. code_puppy/tools/ask_user_question/renderers.py +309 -0
  255. code_puppy/tools/ask_user_question/terminal_ui.py +329 -0
  256. code_puppy/tools/ask_user_question/theme.py +155 -0
  257. code_puppy/tools/ask_user_question/tui_loop.py +423 -0
  258. code_puppy/tools/browser/__init__.py +37 -0
  259. code_puppy/tools/browser/browser_control.py +289 -0
  260. code_puppy/tools/browser/browser_interactions.py +545 -0
  261. code_puppy/tools/browser/browser_locators.py +640 -0
  262. code_puppy/tools/browser/browser_manager.py +378 -0
  263. code_puppy/tools/browser/browser_navigation.py +251 -0
  264. code_puppy/tools/browser/browser_screenshot.py +179 -0
  265. code_puppy/tools/browser/browser_scripts.py +462 -0
  266. code_puppy/tools/browser/browser_workflows.py +221 -0
  267. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  268. code_puppy/tools/browser/terminal_command_tools.py +534 -0
  269. code_puppy/tools/browser/terminal_screenshot_tools.py +552 -0
  270. code_puppy/tools/browser/terminal_tools.py +525 -0
  271. code_puppy/tools/command_runner.py +1346 -0
  272. code_puppy/tools/common.py +1409 -0
  273. code_puppy/tools/display.py +84 -0
  274. code_puppy/tools/file_modifications.py +739 -0
  275. code_puppy/tools/file_operations.py +802 -0
  276. code_puppy/tools/scheduler_tools.py +412 -0
  277. code_puppy/tools/skills_tools.py +251 -0
  278. code_puppy/tools/subagent_context.py +158 -0
  279. code_puppy/tools/tools_content.py +51 -0
  280. code_puppy/tools/universal_constructor.py +889 -0
  281. code_puppy/uvx_detection.py +242 -0
  282. code_puppy/version_checker.py +82 -0
  283. newcode-0.1.1.data/data/code_puppy/models.json +130 -0
  284. newcode-0.1.1.data/data/code_puppy/models_dev_api.json +1 -0
  285. newcode-0.1.1.dist-info/METADATA +154 -0
  286. newcode-0.1.1.dist-info/RECORD +289 -0
  287. newcode-0.1.1.dist-info/WHEEL +4 -0
  288. newcode-0.1.1.dist-info/entry_points.txt +3 -0
  289. newcode-0.1.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,145 @@
1
+ """Prompt Reviewer Agent - Specializes in analyzing and reviewing prompt quality."""
2
+
3
+ from code_puppy.config import get_agent_name
4
+
5
+ from .. import callbacks
6
+ from .base_agent import BaseAgent
7
+
8
+
9
+ class PromptReviewerAgent(BaseAgent):
10
+ """Prompt Reviewer Agent - Analyzes prompts for quality, clarity, and effectiveness."""
11
+
12
+ @property
13
+ def name(self) -> str:
14
+ return "prompt-reviewer"
15
+
16
+ @property
17
+ def display_name(self) -> str:
18
+ return "Prompt Reviewer 📝"
19
+
20
+ @property
21
+ def description(self) -> str:
22
+ return (
23
+ "Specializes in analyzing and reviewing prompt quality. "
24
+ "Assesses clarity, specificity, context completeness, constraint handling, and ambiguity detection."
25
+ )
26
+
27
+ def get_available_tools(self) -> list[str]:
28
+ """Get the list of tools available to the Prompt Reviewer Agent."""
29
+ return [
30
+ "list_files",
31
+ "read_file",
32
+ "grep",
33
+ "agent_share_your_reasoning",
34
+ "agent_run_shell_command",
35
+ ]
36
+
37
+ def get_system_prompt(self) -> str:
38
+ """Get the optimized Prompt Reviewer Agent's system prompt."""
39
+ agent_name = get_agent_name()
40
+
41
+ result = f"""
42
+ You are {agent_name} in Prompt Review Mode, a prompt quality analyst that reviews and improves prompts for clarity, specificity, and effectiveness.
43
+
44
+ ## Core Mission:
45
+ Analyze prompt quality across 5 key dimensions and provide actionable improvements. Focus on practical, immediately applicable feedback.
46
+
47
+ ## Quick Review Framework:
48
+
49
+ ### Quality Dimensions (1-10 scale):
50
+ 1. **Clarity & Specificity**: Unambiguous language, concrete requirements
51
+ 2. **Context Completeness**: Sufficient background, target audience, environment
52
+ 3. **Constraint Handling**: Clear boundaries, technical requirements, limitations
53
+ 4. **Ambiguity Detection**: Vague terms, multiple interpretations, missing edge cases
54
+ 5. **Actionability**: Clear deliverables, success criteria, next steps
55
+
56
+ ### Review Process:
57
+ 1. **Intent Analysis**: Identify core purpose and target users
58
+ 2. **Gap Detection**: Find missing context, constraints, or clarity issues
59
+ 3. **Improvement Design**: Provide specific, actionable enhancements
60
+ 4. **Best Practice Integration**: Share relevant prompt engineering techniques
61
+
62
+ ## Output Template:
63
+ ```
64
+ 📊 **PROMPT QUALITY ASSESSMENT**:
65
+ **Overall Score**: [X]/10 - [Quality Level]
66
+
67
+ 📋 **QUALITY DIMENSIONS**:
68
+ - **Clarity & Specificity**: [X]/10 - [Brief comment]
69
+ - **Context Completeness**: [X]/10 - [Brief comment]
70
+ - **Constraint Handling**: [X]/10 - [Brief comment]
71
+ - **Ambiguity Level**: [X]/10 - [Lower is better, brief comment]
72
+ - **Actionability**: [X]/10 - [Brief comment]
73
+
74
+ 🎯 **STRENGTHS**:
75
+ [2-3 key strengths with examples]
76
+
77
+ ⚠️ **CRITICAL ISSUES**:
78
+ [2-3 major problems with impact]
79
+
80
+ ✨ **IMPROVEMENTS**:
81
+ **Fixes**:
82
+ - [ ] [Specific, actionable improvement 1]
83
+ - [ ] [Specific, actionable improvement 2]
84
+ **Enhancements**:
85
+ - [ ] [Optional improvement 1]
86
+ - [ ] [Optional improvement 2]
87
+
88
+ 🎨 **IMPROVED PROMPT**:
89
+ [Concise, improved version]
90
+
91
+ 🚀 **NEXT STEPS**:
92
+ [Clear implementation guidance]
93
+ ```
94
+
95
+ ## Context Integration:
96
+
97
+ ### When to Use Tools:
98
+ - **list_files**: Prompt references project structure or files
99
+ - **read_file**: Need to analyze existing code or documentation
100
+ - **grep**: Find similar patterns or existing implementations
101
+ - **agent_share_your_reasoning**: Explain complex review decisions
102
+ - **invoke_agent**: Consult domain specialists for context-specific issues
103
+
104
+ ### Project-Aware Analysis:
105
+ - Consider the project's tech stack
106
+ - Account for git workflow and build tooling
107
+ - Adapt to the project's style (clean, concise, DRY)
108
+ - Reference existing patterns in the codebase
109
+
110
+ ## Adaptive Review:
111
+
112
+ ### Prompt Complexity Detection:
113
+ - **Simple (<200 tokens)**: Quick review, focus on core clarity
114
+ - **Medium (200-800 tokens)**: Standard review with context analysis
115
+ - **Complex (>800 tokens)**: Deep analysis, break into components, consider token usage
116
+
117
+ ### Priority Areas by Prompt Type:
118
+ - **Code Generation**: Language specificity, style requirements, testing expectations
119
+ - **Planning**: Timeline realism, resource constraints, risk assessment
120
+ - **Analysis**: Data sources, scope boundaries, output formats
121
+ - **Creative**: Style guidelines, audience constraints, brand requirements
122
+
123
+ ## Common Prompt Patterns:
124
+ - **Vague**: "make it better" → Need for specific success criteria
125
+ - **Missing Context**: "fix this" without specifying what or why
126
+ - **Over-constrained**: Too many conflicting requirements
127
+ - **Under-constrained**: No boundaries leading to scope creep
128
+ - **Assumed Knowledge**: Technical jargon without explanation
129
+
130
+ ## Optimization Principles:
131
+ 1. **Token Efficiency**: Review proportionally to prompt complexity
132
+ 2. **Actionability First**: Prioritize fixes that have immediate impact
133
+ 3. **Context Sensitivity**: Adapt feedback to project environment
134
+ 4. **Iterative Improvement**: Provide stages of enhancement
135
+ 5. **Practical Constraints**: Consider development reality and resource limits
136
+
137
+ You excel at making prompts more effective while respecting practical constraints. Your feedback is constructive, specific, and immediately implementable. Balance thoroughness with efficiency based on prompt complexity and user needs.
138
+
139
+ Remember: Great prompts lead to great results, but perfect is the enemy of good enough.
140
+ """
141
+
142
+ prompt_additions = callbacks.on_load_prompt()
143
+ if len(prompt_additions):
144
+ result += "\n" + "\n".join(prompt_additions)
145
+ return result
@@ -0,0 +1,276 @@
1
+ """Silenced event stream handler for sub-agents.
2
+
3
+ This handler suppresses all console output but still:
4
+ - Updates SubAgentConsoleManager with status/metrics
5
+ - Fires stream_event callbacks for the frontend emitter plugin
6
+ - Tracks tool calls, tokens, and status changes
7
+
8
+ Usage:
9
+ >>> from code_puppy.agents.subagent_stream_handler import subagent_stream_handler
10
+ >>> # In agent run:
11
+ >>> await subagent_stream_handler(ctx, events, session_id="my-session-123")
12
+ """
13
+
14
+ import asyncio
15
+ import logging
16
+ from collections.abc import AsyncIterable
17
+ from typing import Any, Optional
18
+
19
+ from pydantic_ai import PartDeltaEvent, PartEndEvent, PartStartEvent, RunContext
20
+ from pydantic_ai.messages import (
21
+ TextPart,
22
+ TextPartDelta,
23
+ ThinkingPart,
24
+ ThinkingPartDelta,
25
+ ToolCallPart,
26
+ ToolCallPartDelta,
27
+ )
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ # =============================================================================
33
+ # Callback Helper
34
+ # =============================================================================
35
+
36
+
37
+ def _fire_callback(event_type: str, event_data: Any, session_id: Optional[str]) -> None:
38
+ """Fire stream_event callback non-blocking.
39
+
40
+ Schedules the callback to run asynchronously without waiting for it.
41
+ Silently ignores errors if no event loop is running or if the callback
42
+ system is unavailable.
43
+
44
+ Args:
45
+ event_type: Type of the event ('part_start', 'part_delta', 'part_end')
46
+ event_data: Dictionary containing event-specific data
47
+ session_id: Optional session ID for the sub-agent
48
+ """
49
+ try:
50
+ from code_puppy import callbacks
51
+
52
+ loop = asyncio.get_running_loop()
53
+ loop.create_task(callbacks.on_stream_event(event_type, event_data, session_id))
54
+ except RuntimeError:
55
+ # No event loop running - this can happen during shutdown
56
+ logger.debug("No event loop available for stream event callback")
57
+ except ImportError:
58
+ # Callbacks module not available
59
+ logger.debug("Callbacks module not available for stream event")
60
+ except Exception as e:
61
+ # Don't let callback errors break the stream handler
62
+ logger.debug(f"Error firing stream event callback: {e}")
63
+
64
+
65
+ # =============================================================================
66
+ # Token Estimation
67
+ # =============================================================================
68
+
69
+
70
+ def _estimate_tokens(content: str) -> int:
71
+ """Estimate token count from content string.
72
+
73
+ Uses a rough heuristic: ~4 characters per token for English text.
74
+ This is a ballpark estimate - actual tokenization varies by model.
75
+
76
+ Args:
77
+ content: The text content to estimate tokens for
78
+
79
+ Returns:
80
+ Estimated token count (minimum 1 for non-empty content)
81
+ """
82
+ if not content:
83
+ return 0
84
+ # Rough estimate: 4 chars = 1 token, minimum 1 for any content
85
+ return max(1, len(content) // 4)
86
+
87
+
88
+ # =============================================================================
89
+ # Main Handler
90
+ # =============================================================================
91
+
92
+
93
+ async def subagent_stream_handler(
94
+ ctx: RunContext,
95
+ events: AsyncIterable[Any],
96
+ session_id: Optional[str] = None,
97
+ ) -> None:
98
+ """Silent event stream handler for sub-agents.
99
+
100
+ Processes streaming events without producing any console output.
101
+ Updates the SubAgentConsoleManager with status and metrics, and fires
102
+ stream_event callbacks for any registered listeners.
103
+
104
+ Args:
105
+ ctx: The pydantic-ai run context
106
+ events: Async iterable of streaming events (PartStartEvent,
107
+ PartDeltaEvent, PartEndEvent)
108
+ session_id: Session ID of the sub-agent for console manager updates.
109
+ If None, falls back to get_session_context().
110
+ """
111
+ # Late import to avoid circular dependencies
112
+ from code_puppy.messaging import get_session_context
113
+ from code_puppy.messaging.subagent_console import SubAgentConsoleManager
114
+
115
+ manager = SubAgentConsoleManager.get_instance()
116
+
117
+ # Resolve session_id, falling back to context if not provided
118
+ effective_session_id = session_id or get_session_context()
119
+
120
+ # Metrics tracking
121
+ token_count = 0
122
+ tool_call_count = 0
123
+ active_tool_parts: set[int] = set() # Track active tool call indices
124
+
125
+ async for event in events:
126
+ try:
127
+ await _handle_event(
128
+ event=event,
129
+ manager=manager,
130
+ session_id=effective_session_id,
131
+ token_count=token_count,
132
+ tool_call_count=tool_call_count,
133
+ active_tool_parts=active_tool_parts,
134
+ )
135
+
136
+ # Update metrics from returned values
137
+ # (we need to track these at this level since they're modified in _handle_event)
138
+ if isinstance(event, PartStartEvent):
139
+ if isinstance(event.part, ToolCallPart):
140
+ tool_call_count += 1
141
+ active_tool_parts.add(event.index)
142
+
143
+ elif isinstance(event, PartDeltaEvent):
144
+ delta = event.delta
145
+ if isinstance(delta, (TextPartDelta, ThinkingPartDelta)):
146
+ if delta.content_delta:
147
+ token_count += _estimate_tokens(delta.content_delta)
148
+
149
+ elif isinstance(event, PartEndEvent):
150
+ active_tool_parts.discard(event.index)
151
+
152
+ except Exception as e:
153
+ # Log but don't crash on event handling errors
154
+ logger.debug(f"Error handling stream event: {e}")
155
+ continue
156
+
157
+
158
+ async def _handle_event(
159
+ event: Any,
160
+ manager: Any, # SubAgentConsoleManager
161
+ session_id: Optional[str],
162
+ token_count: int,
163
+ tool_call_count: int,
164
+ active_tool_parts: set[int],
165
+ ) -> None:
166
+ """Handle a single streaming event.
167
+
168
+ Updates the console manager and fires callbacks for each event type.
169
+
170
+ Args:
171
+ event: The streaming event to handle
172
+ manager: SubAgentConsoleManager instance
173
+ session_id: Session ID for updates
174
+ token_count: Current token count
175
+ tool_call_count: Current tool call count
176
+ active_tool_parts: Set of active tool call indices
177
+ """
178
+ if session_id is None:
179
+ # Can't update manager without session_id
180
+ logger.debug("No session_id available for stream event")
181
+ return
182
+
183
+ # -------------------------------------------------------------------------
184
+ # PartStartEvent - Track new parts and update status
185
+ # -------------------------------------------------------------------------
186
+ if isinstance(event, PartStartEvent):
187
+ part = event.part
188
+ event_data = {
189
+ "index": event.index,
190
+ "part_type": type(part).__name__,
191
+ }
192
+
193
+ if isinstance(part, ThinkingPart):
194
+ manager.update_agent(session_id, status="thinking")
195
+ event_data["content"] = getattr(part, "content", None)
196
+
197
+ elif isinstance(part, TextPart):
198
+ manager.update_agent(session_id, status="running")
199
+ event_data["content"] = getattr(part, "content", None)
200
+
201
+ elif isinstance(part, ToolCallPart):
202
+ # tool_call_count is updated in the main handler
203
+ manager.update_agent(
204
+ session_id,
205
+ status="tool_calling",
206
+ tool_call_count=tool_call_count + 1, # +1 for this new one
207
+ current_tool=part.tool_name,
208
+ )
209
+ event_data["tool_name"] = part.tool_name
210
+ event_data["tool_call_id"] = getattr(part, "tool_call_id", None)
211
+
212
+ _fire_callback("part_start", event_data, session_id)
213
+
214
+ # -------------------------------------------------------------------------
215
+ # PartDeltaEvent - Track content deltas and update metrics
216
+ # -------------------------------------------------------------------------
217
+ elif isinstance(event, PartDeltaEvent):
218
+ delta = event.delta
219
+ event_data = {
220
+ "index": event.index,
221
+ "delta_type": type(delta).__name__,
222
+ }
223
+
224
+ if isinstance(delta, TextPartDelta):
225
+ content_delta = delta.content_delta
226
+ if content_delta:
227
+ # Token count is updated in main handler
228
+ new_token_count = token_count + _estimate_tokens(content_delta)
229
+ manager.update_agent(session_id, token_count=new_token_count)
230
+ event_data["content_delta"] = content_delta
231
+
232
+ elif isinstance(delta, ThinkingPartDelta):
233
+ content_delta = delta.content_delta
234
+ if content_delta:
235
+ new_token_count = token_count + _estimate_tokens(content_delta)
236
+ manager.update_agent(session_id, token_count=new_token_count)
237
+ event_data["content_delta"] = content_delta
238
+
239
+ elif isinstance(delta, ToolCallPartDelta):
240
+ # Tool call deltas might have partial args
241
+ event_data["args_delta"] = getattr(delta, "args_delta", None)
242
+ event_data["tool_name_delta"] = getattr(delta, "tool_name_delta", None)
243
+
244
+ _fire_callback("part_delta", event_data, session_id)
245
+
246
+ # -------------------------------------------------------------------------
247
+ # PartEndEvent - Track part completion and update status
248
+ # -------------------------------------------------------------------------
249
+ elif isinstance(event, PartEndEvent):
250
+ event_data = {
251
+ "index": event.index,
252
+ "next_part_kind": getattr(event, "next_part_kind", None),
253
+ }
254
+
255
+ # If this was a tool call part ending, check if we should reset status
256
+ if event.index in active_tool_parts:
257
+ # Remove this index from active parts (done in main handler)
258
+ # If no more active tool parts after removal, reset to running
259
+ remaining_active = active_tool_parts - {event.index}
260
+ if not remaining_active:
261
+ manager.update_agent(
262
+ session_id,
263
+ current_tool=None,
264
+ status="running",
265
+ )
266
+
267
+ _fire_callback("part_end", event_data, session_id)
268
+
269
+
270
+ # =============================================================================
271
+ # Exports
272
+ # =============================================================================
273
+
274
+ __all__ = [
275
+ "subagent_stream_handler",
276
+ ]
@@ -0,0 +1,13 @@
1
+ """REST API module.
2
+
3
+ This module provides a FastAPI-based REST API for the application configuration,
4
+ sessions, commands, and real-time WebSocket communication.
5
+
6
+ Exports:
7
+ create_app: Factory function to create the FastAPI application
8
+ main: Entry point to run the server
9
+ """
10
+
11
+ from code_puppy.api.app import create_app
12
+
13
+ __all__ = ["create_app"]
code_puppy/api/app.py ADDED
@@ -0,0 +1,169 @@
1
+ """FastAPI application factory."""
2
+
3
+ import asyncio
4
+ import logging
5
+ from contextlib import asynccontextmanager
6
+ from pathlib import Path
7
+ from typing import AsyncGenerator
8
+
9
+ from fastapi import FastAPI, Request
10
+ from fastapi.middleware.cors import CORSMiddleware
11
+ from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
12
+ from starlette.middleware.base import BaseHTTPMiddleware
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Default request timeout (seconds) - fail fast!
17
+ REQUEST_TIMEOUT = 30.0
18
+
19
+
20
+ class TimeoutMiddleware(BaseHTTPMiddleware):
21
+ """Middleware to enforce request timeouts and prevent hanging requests."""
22
+
23
+ def __init__(self, app, timeout: float = REQUEST_TIMEOUT):
24
+ super().__init__(app)
25
+ self.timeout = timeout
26
+
27
+ async def dispatch(self, request: Request, call_next):
28
+ # Skip timeout for WebSocket upgrades and streaming endpoints
29
+ if request.headers.get(
30
+ "upgrade", ""
31
+ ).lower() == "websocket" or request.url.path.startswith("/ws/"):
32
+ return await call_next(request)
33
+
34
+ try:
35
+ return await asyncio.wait_for(
36
+ call_next(request),
37
+ timeout=self.timeout,
38
+ )
39
+ except asyncio.TimeoutError:
40
+ return JSONResponse(
41
+ status_code=504,
42
+ content={
43
+ "detail": f"Request timed out after {self.timeout}s",
44
+ "error": "timeout",
45
+ },
46
+ )
47
+
48
+
49
+ @asynccontextmanager
50
+ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
51
+ """Lifespan context manager for startup and shutdown events.
52
+
53
+ Handles graceful cleanup of resources when the server shuts down.
54
+ """
55
+ # Startup: nothing special needed yet, but this is where you'd do it
56
+ logger.info("API starting up...")
57
+ yield
58
+ # Shutdown: clean up all the things!
59
+ logger.info("API shutting down, cleaning up...")
60
+
61
+ # 1. Close all PTY sessions
62
+ try:
63
+ from code_puppy.api.pty_manager import get_pty_manager
64
+
65
+ pty_manager = get_pty_manager()
66
+ await pty_manager.close_all()
67
+ logger.info("✓ All PTY sessions closed")
68
+ except Exception as e:
69
+ logger.error(f"Error closing PTY sessions: {e}")
70
+
71
+ # 2. Remove PID file so /api status knows we're gone
72
+ try:
73
+ from code_puppy.config import STATE_DIR
74
+
75
+ pid_file = Path(STATE_DIR) / "api_server.pid"
76
+ if pid_file.exists():
77
+ pid_file.unlink()
78
+ logger.info("✓ PID file removed")
79
+ except Exception as e:
80
+ logger.error(f"Error removing PID file: {e}")
81
+
82
+
83
+ def create_app() -> FastAPI:
84
+ """Create and configure the FastAPI application."""
85
+ app = FastAPI(
86
+ lifespan=lifespan,
87
+ title="Code Agent API",
88
+ description="REST API and Interactive Terminal",
89
+ version="1.0.0",
90
+ docs_url="/docs",
91
+ redoc_url="/redoc",
92
+ )
93
+
94
+ # Timeout middleware - added first so it wraps everything
95
+ app.add_middleware(TimeoutMiddleware, timeout=REQUEST_TIMEOUT)
96
+
97
+ # CORS middleware for frontend access
98
+ app.add_middleware(
99
+ CORSMiddleware,
100
+ allow_origins=["*"], # Local/trusted
101
+ allow_credentials=True,
102
+ allow_methods=["*"],
103
+ allow_headers=["*"],
104
+ )
105
+
106
+ # Include routers
107
+ from code_puppy.api.routers import agents, commands, config, sessions
108
+
109
+ app.include_router(config.router, prefix="/api/config", tags=["config"])
110
+ app.include_router(commands.router, prefix="/api/commands", tags=["commands"])
111
+ app.include_router(sessions.router, prefix="/api/sessions", tags=["sessions"])
112
+ app.include_router(agents.router, prefix="/api/agents", tags=["agents"])
113
+
114
+ # WebSocket endpoints (events + terminal)
115
+ from code_puppy.api.websocket import setup_websocket
116
+
117
+ setup_websocket(app)
118
+
119
+ # Templates directory
120
+ templates_dir = Path(__file__).parent / "templates"
121
+
122
+ @app.get("/")
123
+ async def root():
124
+ """Landing page with links to terminal and docs."""
125
+ return HTMLResponse(
126
+ content="""
127
+ <!DOCTYPE html>
128
+ <html>
129
+ <head>
130
+ <title>Code Agent</title>
131
+ <script src="https://cdn.tailwindcss.com"></script>
132
+ </head>
133
+ <body class="bg-gray-900 text-white min-h-screen flex items-center justify-center">
134
+ <div class="text-center">
135
+ <h1 class="text-6xl mb-4">&#x2699;</h1>
136
+ <h2 class="text-3xl font-bold mb-8">Code Agent</h2>
137
+ <div class="space-x-4">
138
+ <a href="/terminal" class="px-6 py-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-lg font-semibold">
139
+ Open Terminal
140
+ </a>
141
+ <a href="/docs" class="px-6 py-3 bg-gray-700 hover:bg-gray-600 rounded-lg text-lg">
142
+ API Docs
143
+ </a>
144
+ </div>
145
+ <p class="mt-8 text-gray-400">
146
+ WebSocket: ws://localhost:8765/ws/terminal
147
+ </p>
148
+ </div>
149
+ </body>
150
+ </html>
151
+ """
152
+ )
153
+
154
+ @app.get("/terminal")
155
+ async def terminal_page():
156
+ """Serve the interactive terminal page."""
157
+ html_file = templates_dir / "terminal.html"
158
+ if html_file.exists():
159
+ return FileResponse(html_file, media_type="text/html")
160
+ return HTMLResponse(
161
+ content="<h1>Terminal template not found</h1>",
162
+ status_code=404,
163
+ )
164
+
165
+ @app.get("/health")
166
+ async def health():
167
+ return {"status": "healthy"}
168
+
169
+ return app
code_puppy/api/main.py ADDED
@@ -0,0 +1,21 @@
1
+ """Entry point for running the FastAPI server."""
2
+
3
+ import uvicorn
4
+
5
+ from code_puppy.api.app import create_app
6
+
7
+ app = create_app()
8
+
9
+
10
+ def main(host: str = "127.0.0.1", port: int = 8765) -> None:
11
+ """Run the FastAPI server.
12
+
13
+ Args:
14
+ host: The host address to bind to. Defaults to localhost.
15
+ port: The port number to listen on. Defaults to 8765.
16
+ """
17
+ uvicorn.run(app, host=host, port=port)
18
+
19
+
20
+ if __name__ == "__main__":
21
+ main()