iCode-TUI 0.29.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 (1138) hide show
  1. chrys/__init__.py +16 -0
  2. chrys/app/__init__.py +3 -0
  3. chrys/app/acp/__init__.py +3 -0
  4. chrys/app/acp/bridge.py +664 -0
  5. chrys/app/acp/content.py +132 -0
  6. chrys/app/acp/doc/frontend-api.md +425 -0
  7. chrys/app/acp/history.py +585 -0
  8. chrys/app/acp/server.py +1796 -0
  9. chrys/app/acp/session_manager.py +1815 -0
  10. chrys/app/acp/tool_status.py +45 -0
  11. chrys/app/cli/__init__.py +3 -0
  12. chrys/app/cli/acp.py +178 -0
  13. chrys/app/cli/app.py +165 -0
  14. chrys/app/cli/approvals.py +101 -0
  15. chrys/app/cli/headless.py +223 -0
  16. chrys/app/cli/launch_cwd.py +42 -0
  17. chrys/app/cli/profiles.py +298 -0
  18. chrys/app/cli/progress.py +857 -0
  19. chrys/app/cli/run.py +425 -0
  20. chrys/app/cli/serve.py +1593 -0
  21. chrys/app/cli/tool_summary.py +225 -0
  22. chrys/app/cli/trajectory.py +201 -0
  23. chrys/app/cli/workflow.py +601 -0
  24. chrys/app/features/__init__.py +3 -0
  25. chrys/app/features/buddy/__init__.py +3 -0
  26. chrys/app/features/buddy/actions.py +68 -0
  27. chrys/app/features/buddy/animation.py +76 -0
  28. chrys/app/features/buddy/commands.py +196 -0
  29. chrys/app/features/buddy/docs/design.md +187 -0
  30. chrys/app/features/buddy/hatchery.py +80 -0
  31. chrys/app/features/buddy/lifecycle.py +41 -0
  32. chrys/app/features/buddy/model.py +265 -0
  33. chrys/app/features/buddy/pixel_renderer.py +113 -0
  34. chrys/app/features/buddy/pixel_sprites.py +279 -0
  35. chrys/app/features/buddy/portrait.py +76 -0
  36. chrys/app/features/buddy/progression.py +58 -0
  37. chrys/app/features/buddy/replies.py +191 -0
  38. chrys/app/features/buddy/sprites/alien.toml +70 -0
  39. chrys/app/features/buddy/sprites/axolotl.toml +71 -0
  40. chrys/app/features/buddy/sprites/bat.toml +69 -0
  41. chrys/app/features/buddy/sprites/bee.toml +69 -0
  42. chrys/app/features/buddy/sprites/cactus.toml +73 -0
  43. chrys/app/features/buddy/sprites/capybara.toml +70 -0
  44. chrys/app/features/buddy/sprites/cat.toml +69 -0
  45. chrys/app/features/buddy/sprites/crab.toml +70 -0
  46. chrys/app/features/buddy/sprites/dragon.toml +71 -0
  47. chrys/app/features/buddy/sprites/duck.toml +69 -0
  48. chrys/app/features/buddy/sprites/fox.toml +69 -0
  49. chrys/app/features/buddy/sprites/frog.toml +70 -0
  50. chrys/app/features/buddy/sprites/ghost.toml +70 -0
  51. chrys/app/features/buddy/sprites/goose.toml +69 -0
  52. chrys/app/features/buddy/sprites/jelly.toml +70 -0
  53. chrys/app/features/buddy/sprites/llama.toml +70 -0
  54. chrys/app/features/buddy/sprites/mushroom.toml +69 -0
  55. chrys/app/features/buddy/sprites/octopus.toml +70 -0
  56. chrys/app/features/buddy/sprites/owl.toml +70 -0
  57. chrys/app/features/buddy/sprites/panda.toml +71 -0
  58. chrys/app/features/buddy/sprites/penguin.toml +69 -0
  59. chrys/app/features/buddy/sprites/rabbit.toml +70 -0
  60. chrys/app/features/buddy/sprites/robot.toml +72 -0
  61. chrys/app/features/buddy/sprites/shark.toml +70 -0
  62. chrys/app/features/buddy/sprites/snail.toml +69 -0
  63. chrys/app/features/buddy/sprites/snake.toml +69 -0
  64. chrys/app/features/buddy/sprites/tabby.toml +69 -0
  65. chrys/app/features/buddy/sprites/turtle.toml +69 -0
  66. chrys/app/features/buddy/store.py +143 -0
  67. chrys/app/features/session_title/__init__.py +7 -0
  68. chrys/app/features/session_title/updater.py +582 -0
  69. chrys/app/installer.py +651 -0
  70. chrys/app/parsing.py +17 -0
  71. chrys/app/tui/__init__.py +3 -0
  72. chrys/app/tui/app.py +1287 -0
  73. chrys/app/tui/behaviors/__init__.py +3 -0
  74. chrys/app/tui/behaviors/click_outside_dismiss.py +90 -0
  75. chrys/app/tui/behaviors/insert_clipboard.py +73 -0
  76. chrys/app/tui/behaviors/right_click_copy.py +146 -0
  77. chrys/app/tui/binding_display.py +139 -0
  78. chrys/app/tui/buddy_messages.py +17 -0
  79. chrys/app/tui/buddy_reply.py +86 -0
  80. chrys/app/tui/chrys.tcss +549 -0
  81. chrys/app/tui/clipboard.py +109 -0
  82. chrys/app/tui/copy_messages.py +10 -0
  83. chrys/app/tui/i18n.py +230 -0
  84. chrys/app/tui/language.py +58 -0
  85. chrys/app/tui/notifications/__init__.py +12 -0
  86. chrys/app/tui/notifications/drivers.py +180 -0
  87. chrys/app/tui/notifications/service.py +126 -0
  88. chrys/app/tui/notifications/settings.py +141 -0
  89. chrys/app/tui/screens/__init__.py +3 -0
  90. chrys/app/tui/screens/agents/__init__.py +8 -0
  91. chrys/app/tui/screens/agents/agent_draft_store.py +937 -0
  92. chrys/app/tui/screens/agents/config.py +2142 -0
  93. chrys/app/tui/screens/agents/config.tcss +169 -0
  94. chrys/app/tui/screens/agents/panels/__init__.py +3 -0
  95. chrys/app/tui/screens/agents/panels/acp.py +1176 -0
  96. chrys/app/tui/screens/agents/panels/basic.py +497 -0
  97. chrys/app/tui/screens/agents/panels/compaction.py +231 -0
  98. chrys/app/tui/screens/agents/panels/config_card.py +218 -0
  99. chrys/app/tui/screens/agents/panels/instructions.py +91 -0
  100. chrys/app/tui/screens/agents/panels/markdown_report.py +76 -0
  101. chrys/app/tui/screens/agents/panels/mcp.py +2262 -0
  102. chrys/app/tui/screens/agents/panels/memory.py +684 -0
  103. chrys/app/tui/screens/agents/panels/path_entry.py +227 -0
  104. chrys/app/tui/screens/agents/panels/skills.py +806 -0
  105. chrys/app/tui/screens/agents/panels/subagents.py +652 -0
  106. chrys/app/tui/screens/agents/panels/tools.py +205 -0
  107. chrys/app/tui/screens/agents/picker.py +103 -0
  108. chrys/app/tui/screens/agents/skill_paths.py +38 -0
  109. chrys/app/tui/screens/agents/validation_messages.py +452 -0
  110. chrys/app/tui/screens/dialogs/__init__.py +35 -0
  111. chrys/app/tui/screens/dialogs/agent_load.py +834 -0
  112. chrys/app/tui/screens/dialogs/agent_load.tcss +78 -0
  113. chrys/app/tui/screens/dialogs/app_mode.py +55 -0
  114. chrys/app/tui/screens/dialogs/approval/__init__.py +15 -0
  115. chrys/app/tui/screens/dialogs/approval/approval.tcss +311 -0
  116. chrys/app/tui/screens/dialogs/approval/bodies/__init__.py +3 -0
  117. chrys/app/tui/screens/dialogs/approval/bodies/file_edit.py +210 -0
  118. chrys/app/tui/screens/dialogs/approval/bodies/sub_agent.py +82 -0
  119. chrys/app/tui/screens/dialogs/approval/body.py +110 -0
  120. chrys/app/tui/screens/dialogs/approval/dialog.py +565 -0
  121. chrys/app/tui/screens/dialogs/approval/mode.py +105 -0
  122. chrys/app/tui/screens/dialogs/ask_user.py +148 -0
  123. chrys/app/tui/screens/dialogs/ask_user.tcss +62 -0
  124. chrys/app/tui/screens/dialogs/base.py +84 -0
  125. chrys/app/tui/screens/dialogs/confirm.py +184 -0
  126. chrys/app/tui/screens/dialogs/confirm.tcss +46 -0
  127. chrys/app/tui/screens/dialogs/connection_test.py +183 -0
  128. chrys/app/tui/screens/dialogs/connection_test.tcss +92 -0
  129. chrys/app/tui/screens/dialogs/diagram.py +102 -0
  130. chrys/app/tui/screens/dialogs/diagram.tcss +24 -0
  131. chrys/app/tui/screens/dialogs/editor.py +378 -0
  132. chrys/app/tui/screens/dialogs/editor.tcss +132 -0
  133. chrys/app/tui/screens/dialogs/file_picker.py +582 -0
  134. chrys/app/tui/screens/dialogs/file_picker.tcss +78 -0
  135. chrys/app/tui/screens/dialogs/fork_session.py +219 -0
  136. chrys/app/tui/screens/dialogs/fork_session.tcss +75 -0
  137. chrys/app/tui/screens/dialogs/image_compression.py +102 -0
  138. chrys/app/tui/screens/dialogs/image_compression.tcss +28 -0
  139. chrys/app/tui/screens/dialogs/man_page.py +172 -0
  140. chrys/app/tui/screens/dialogs/man_page.tcss +39 -0
  141. chrys/app/tui/screens/dialogs/new_folder.py +277 -0
  142. chrys/app/tui/screens/dialogs/new_folder.tcss +51 -0
  143. chrys/app/tui/screens/dialogs/notice.tcss +14 -0
  144. chrys/app/tui/screens/dialogs/prompt_cache.py +144 -0
  145. chrys/app/tui/screens/dialogs/prompt_cache.tcss +38 -0
  146. chrys/app/tui/screens/dialogs/runtime_details.py +371 -0
  147. chrys/app/tui/screens/dialogs/runtime_details.tcss +49 -0
  148. chrys/app/tui/screens/dialogs/session_title.py +110 -0
  149. chrys/app/tui/screens/dialogs/session_title.tcss +43 -0
  150. chrys/app/tui/screens/dialogs/tool_view.py +207 -0
  151. chrys/app/tui/screens/dialogs/tool_view.tcss +43 -0
  152. chrys/app/tui/screens/dialogs/vision_unsupported.py +122 -0
  153. chrys/app/tui/screens/dialogs/vision_unsupported.tcss +35 -0
  154. chrys/app/tui/screens/dialogs/workflow_confirm.py +91 -0
  155. chrys/app/tui/screens/dialogs/workflow_confirm.tcss +17 -0
  156. chrys/app/tui/screens/dialogs/workflow_input.py +258 -0
  157. chrys/app/tui/screens/dialogs/workflow_input.tcss +73 -0
  158. chrys/app/tui/screens/dialogs/workflow_node.py +462 -0
  159. chrys/app/tui/screens/dialogs/workflow_node.tcss +41 -0
  160. chrys/app/tui/screens/dialogs/workflow_picker.py +46 -0
  161. chrys/app/tui/screens/dialogs/workflow_result.py +136 -0
  162. chrys/app/tui/screens/dialogs/workflow_result.tcss +14 -0
  163. chrys/app/tui/screens/diff/__init__.py +22 -0
  164. chrys/app/tui/screens/diff/rollback_modal.py +1381 -0
  165. chrys/app/tui/screens/diff/rollback_modal.tcss +248 -0
  166. chrys/app/tui/screens/diff/screen.py +1532 -0
  167. chrys/app/tui/screens/diff/screen.tcss +104 -0
  168. chrys/app/tui/screens/guides/__init__.py +7 -0
  169. chrys/app/tui/screens/guides/_docs/en/guides/configuration/agents.md +178 -0
  170. chrys/app/tui/screens/guides/_docs/en/guides/configuration/approval.md +117 -0
  171. chrys/app/tui/screens/guides/_docs/en/guides/configuration/chat-options.md +276 -0
  172. chrys/app/tui/screens/guides/_docs/en/guides/configuration/compaction.md +42 -0
  173. chrys/app/tui/screens/guides/_docs/en/guides/configuration/memory.md +48 -0
  174. chrys/app/tui/screens/guides/_docs/en/guides/configuration/models.md +158 -0
  175. chrys/app/tui/screens/guides/_docs/en/guides/configuration/settings.md +210 -0
  176. chrys/app/tui/screens/guides/_docs/en/guides/configuration/themes.md +61 -0
  177. chrys/app/tui/screens/guides/_docs/en/guides/configuration/tools.md +60 -0
  178. chrys/app/tui/screens/guides/_docs/en/guides/configuration/web-tools.md +286 -0
  179. chrys/app/tui/screens/guides/_docs/en/guides/daily-use/sessions.md +77 -0
  180. chrys/app/tui/screens/guides/_docs/en/guides/daily-use/workspaces.md +51 -0
  181. chrys/app/tui/screens/guides/_docs/en/guides/extensions/external-acp-agents.md +126 -0
  182. chrys/app/tui/screens/guides/_docs/en/guides/extensions/hooks.md +167 -0
  183. chrys/app/tui/screens/guides/_docs/en/guides/extensions/mcp.md +95 -0
  184. chrys/app/tui/screens/guides/_docs/en/guides/extensions/skills.md +175 -0
  185. chrys/app/tui/screens/guides/_docs/en/guides/running/icode-acp.md +61 -0
  186. chrys/app/tui/screens/guides/_docs/en/guides/running/icode-run.md +190 -0
  187. chrys/app/tui/screens/guides/_docs/en/guides/running/icode-serve.md +239 -0
  188. chrys/app/tui/screens/guides/_docs/en/guides/running/workflows.md +664 -0
  189. chrys/app/tui/screens/guides/_docs/en/reference/agent-profile.md +548 -0
  190. chrys/app/tui/screens/guides/_docs/en/reference/hooks.md +602 -0
  191. chrys/app/tui/screens/guides/_docs/en/reference/opentelemetry.md +177 -0
  192. chrys/app/tui/screens/guides/_docs/en/reference/settings.md +245 -0
  193. chrys/app/tui/screens/guides/_docs/en/reference/themes.md +149 -0
  194. chrys/app/tui/screens/guides/_docs/en/reference/tool-kinds-and-names.md +58 -0
  195. chrys/app/tui/screens/guides/_docs/en/reference/tui-slash-commands.md +76 -0
  196. chrys/app/tui/screens/guides/_docs/en/reference/workflows.md +1006 -0
  197. chrys/app/tui/screens/guides/_docs/en/start/getting-started.md +170 -0
  198. chrys/app/tui/screens/guides/_docs/en/start/what-is-icode.md +34 -0
  199. chrys/app/tui/screens/guides/_docs/index.yaml +100 -0
  200. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/agents.md +178 -0
  201. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/approval.md +117 -0
  202. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/chat-options.md +276 -0
  203. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/compaction.md +42 -0
  204. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/memory.md +48 -0
  205. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/models.md +158 -0
  206. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/settings.md +210 -0
  207. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/themes.md +61 -0
  208. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/tools.md +60 -0
  209. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/web-tools.md +286 -0
  210. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/daily-use/sessions.md +77 -0
  211. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/daily-use/workspaces.md +51 -0
  212. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/external-acp-agents.md +126 -0
  213. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/hooks.md +167 -0
  214. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/mcp.md +95 -0
  215. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/skills.md +175 -0
  216. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-acp.md +61 -0
  217. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-run.md +190 -0
  218. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-serve.md +239 -0
  219. chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/workflows.md +664 -0
  220. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/agent-profile.md +548 -0
  221. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/hooks.md +602 -0
  222. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/opentelemetry.md +177 -0
  223. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/settings.md +245 -0
  224. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/themes.md +149 -0
  225. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/tool-kinds-and-names.md +58 -0
  226. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/tui-slash-commands.md +76 -0
  227. chrys/app/tui/screens/guides/_docs/zh-Hans/reference/workflows.md +1005 -0
  228. chrys/app/tui/screens/guides/_docs/zh-Hans/start/getting-started.md +170 -0
  229. chrys/app/tui/screens/guides/_docs/zh-Hans/start/what-is-icode.md +34 -0
  230. chrys/app/tui/screens/guides/index.py +215 -0
  231. chrys/app/tui/screens/guides/reader.py +173 -0
  232. chrys/app/tui/screens/guides/screen.py +442 -0
  233. chrys/app/tui/screens/guides/screen.tcss +52 -0
  234. chrys/app/tui/screens/logs/__init__.py +7 -0
  235. chrys/app/tui/screens/logs/screen.py +504 -0
  236. chrys/app/tui/screens/logs/screen.tcss +45 -0
  237. chrys/app/tui/screens/main/__init__.py +7 -0
  238. chrys/app/tui/screens/main/action_availability.py +30 -0
  239. chrys/app/tui/screens/main/buddy_command.py +143 -0
  240. chrys/app/tui/screens/main/commands.py +1073 -0
  241. chrys/app/tui/screens/main/config_actions.py +464 -0
  242. chrys/app/tui/screens/main/copy_actions.py +117 -0
  243. chrys/app/tui/screens/main/dialog_controllers.py +826 -0
  244. chrys/app/tui/screens/main/dialog_gateway.py +166 -0
  245. chrys/app/tui/screens/main/diff_controller.py +478 -0
  246. chrys/app/tui/screens/main/engine_read_model.py +184 -0
  247. chrys/app/tui/screens/main/event_handlers.py +2014 -0
  248. chrys/app/tui/screens/main/input_flow.py +241 -0
  249. chrys/app/tui/screens/main/live_diff.py +244 -0
  250. chrys/app/tui/screens/main/main_screen_presenter.py +295 -0
  251. chrys/app/tui/screens/main/model_indicator.py +217 -0
  252. chrys/app/tui/screens/main/navigation.py +343 -0
  253. chrys/app/tui/screens/main/ports.py +571 -0
  254. chrys/app/tui/screens/main/recent_dirs.py +123 -0
  255. chrys/app/tui/screens/main/rollback_controller.py +586 -0
  256. chrys/app/tui/screens/main/runtime_info.py +71 -0
  257. chrys/app/tui/screens/main/screen.py +2265 -0
  258. chrys/app/tui/screens/main/screen.tcss +21 -0
  259. chrys/app/tui/screens/main/session_handlers.py +1127 -0
  260. chrys/app/tui/screens/main/session_title.py +239 -0
  261. chrys/app/tui/screens/main/settings_coordinator.py +365 -0
  262. chrys/app/tui/screens/main/settings_persistence.py +184 -0
  263. chrys/app/tui/screens/main/shell_mode.py +112 -0
  264. chrys/app/tui/screens/main/state.py +289 -0
  265. chrys/app/tui/screens/main/submit_state.py +11 -0
  266. chrys/app/tui/screens/main/subscriptions.py +177 -0
  267. chrys/app/tui/screens/main/suggestions.py +982 -0
  268. chrys/app/tui/screens/main/tool_action_bridge.py +75 -0
  269. chrys/app/tui/screens/main/view_adapter.py +1567 -0
  270. chrys/app/tui/screens/main/workflow_browser.py +747 -0
  271. chrys/app/tui/screens/main/workflow_content.py +248 -0
  272. chrys/app/tui/screens/main/workflow_controller.py +240 -0
  273. chrys/app/tui/screens/main/workflow_feedback.py +137 -0
  274. chrys/app/tui/screens/main/workflow_flow.py +49 -0
  275. chrys/app/tui/screens/main/workflow_run_control.py +456 -0
  276. chrys/app/tui/screens/main/workflow_session_view.py +316 -0
  277. chrys/app/tui/screens/main/workspace_actions.py +272 -0
  278. chrys/app/tui/screens/main/workspace_branch.py +194 -0
  279. chrys/app/tui/screens/menus/__init__.py +8 -0
  280. chrys/app/tui/screens/menus/languages.py +114 -0
  281. chrys/app/tui/screens/models/__init__.py +7 -0
  282. chrys/app/tui/screens/models/picker.py +147 -0
  283. chrys/app/tui/screens/models/screen.py +2043 -0
  284. chrys/app/tui/screens/models/screen.tcss +255 -0
  285. chrys/app/tui/screens/sessions/__init__.py +8 -0
  286. chrys/app/tui/screens/sessions/presenter.py +586 -0
  287. chrys/app/tui/screens/sessions/screen.py +779 -0
  288. chrys/app/tui/screens/sessions/screen.tcss +127 -0
  289. chrys/app/tui/screens/settings/__init__.py +29 -0
  290. chrys/app/tui/screens/settings/danger.py +26 -0
  291. chrys/app/tui/screens/settings/dialog.py +281 -0
  292. chrys/app/tui/screens/settings/layout.py +519 -0
  293. chrys/app/tui/screens/settings/migrate_dialog.py +253 -0
  294. chrys/app/tui/screens/settings/panes/__init__.py +3 -0
  295. chrys/app/tui/screens/settings/panes/notifications.py +248 -0
  296. chrys/app/tui/screens/settings/panes/sessions.py +148 -0
  297. chrys/app/tui/screens/settings/ports.py +55 -0
  298. chrys/app/tui/screens/settings/provenance.py +102 -0
  299. chrys/app/tui/screens/settings/rows.py +546 -0
  300. chrys/app/tui/screens/settings/settings.tcss +406 -0
  301. chrys/app/tui/screens/themes/__init__.py +8 -0
  302. chrys/app/tui/screens/themes/dialogs.py +330 -0
  303. chrys/app/tui/screens/themes/editor.py +632 -0
  304. chrys/app/tui/screens/themes/editor.tcss +268 -0
  305. chrys/app/tui/screens/themes/messages.py +95 -0
  306. chrys/app/tui/screens/themes/palette.py +694 -0
  307. chrys/app/tui/screens/themes/panel.py +113 -0
  308. chrys/app/tui/screens/themes/picker.py +203 -0
  309. chrys/app/tui/screens/themes/save.py +191 -0
  310. chrys/app/tui/support/__init__.py +3 -0
  311. chrys/app/tui/support/file_manager.py +64 -0
  312. chrys/app/tui/support/gc_freeze.py +1114 -0
  313. chrys/app/tui/support/path_shortcuts.py +50 -0
  314. chrys/app/tui/support/prompt_history.py +298 -0
  315. chrys/app/tui/support/workspace_mru.py +476 -0
  316. chrys/app/tui/terminal/__init__.py +6 -0
  317. chrys/app/tui/terminal/_pty_backend.py +114 -0
  318. chrys/app/tui/terminal/emulator/__init__.py +24 -0
  319. chrys/app/tui/terminal/emulator/buffer.py +456 -0
  320. chrys/app/tui/terminal/emulator/charsets.py +113 -0
  321. chrys/app/tui/terminal/emulator/core.py +963 -0
  322. chrys/app/tui/terminal/emulator/input.py +342 -0
  323. chrys/app/tui/terminal/emulator/parser.py +227 -0
  324. chrys/app/tui/terminal/emulator/pen.py +158 -0
  325. chrys/app/tui/terminal/launcher.py +455 -0
  326. chrys/app/tui/terminal/leaked_reports.py +44 -0
  327. chrys/app/tui/terminal/panel.py +323 -0
  328. chrys/app/tui/terminal/pty_process.py +405 -0
  329. chrys/app/tui/terminal/rendering.py +151 -0
  330. chrys/app/tui/terminal/shell.py +273 -0
  331. chrys/app/tui/terminal/shell_integration.py +199 -0
  332. chrys/app/tui/terminal/title.py +224 -0
  333. chrys/app/tui/terminal/widget.py +654 -0
  334. chrys/app/tui/theme.py +422 -0
  335. chrys/app/tui/theme_loader.py +201 -0
  336. chrys/app/tui/theme_stylesheet.py +49 -0
  337. chrys/app/tui/themes/__init__.py +3 -0
  338. chrys/app/tui/themes/document.py +120 -0
  339. chrys/app/tui/themes/preview.py +170 -0
  340. chrys/app/tui/themes/store.py +176 -0
  341. chrys/app/tui/toasts.py +69 -0
  342. chrys/app/tui/util/__init__.py +3 -0
  343. chrys/app/tui/util/context_pressure.py +146 -0
  344. chrys/app/tui/util/debug_log.py +292 -0
  345. chrys/app/tui/util/diff_entries.py +64 -0
  346. chrys/app/tui/util/formatting.py +53 -0
  347. chrys/app/tui/util/git_branch.py +326 -0
  348. chrys/app/tui/util/invocation_progress.py +57 -0
  349. chrys/app/tui/util/logo.py +32 -0
  350. chrys/app/tui/util/message_gate.py +35 -0
  351. chrys/app/tui/util/mutation_sources.py +14 -0
  352. chrys/app/tui/util/picker_text.py +27 -0
  353. chrys/app/tui/util/removal.py +47 -0
  354. chrys/app/tui/util/rich_style.py +36 -0
  355. chrys/app/tui/util/source_text.py +12 -0
  356. chrys/app/tui/util/static_update.py +88 -0
  357. chrys/app/tui/util/todo_format.py +51 -0
  358. chrys/app/tui/util/visibility.py +214 -0
  359. chrys/app/tui/widgets/__init__.py +60 -0
  360. chrys/app/tui/widgets/ask_user_controls.py +652 -0
  361. chrys/app/tui/widgets/ask_user_markdown.py +17 -0
  362. chrys/app/tui/widgets/ask_user_prompt.py +606 -0
  363. chrys/app/tui/widgets/buttons.py +52 -0
  364. chrys/app/tui/widgets/chat/__init__.py +3 -0
  365. chrys/app/tui/widgets/chat/agent_transcript_surface.py +818 -0
  366. chrys/app/tui/widgets/chat/chrome.py +296 -0
  367. chrys/app/tui/widgets/chat/compaction_card.py +353 -0
  368. chrys/app/tui/widgets/chat/context_fold.py +77 -0
  369. chrys/app/tui/widgets/chat/file_snapshot.py +91 -0
  370. chrys/app/tui/widgets/chat/image_preview.py +214 -0
  371. chrys/app/tui/widgets/chat/live_renderer.py +383 -0
  372. chrys/app/tui/widgets/chat/messages.py +1039 -0
  373. chrys/app/tui/widgets/chat/panel.py +1769 -0
  374. chrys/app/tui/widgets/chat/ports.py +245 -0
  375. chrys/app/tui/widgets/chat/renderers/__init__.py +7 -0
  376. chrys/app/tui/widgets/chat/renderers/ask_user.py +747 -0
  377. chrys/app/tui/widgets/chat/renderers/execute.py +431 -0
  378. chrys/app/tui/widgets/chat/renderers/file_edit.py +925 -0
  379. chrys/app/tui/widgets/chat/renderers/hosted_code.py +83 -0
  380. chrys/app/tui/widgets/chat/renderers/hosted_generic.py +330 -0
  381. chrys/app/tui/widgets/chat/renderers/hosted_image.py +107 -0
  382. chrys/app/tui/widgets/chat/renderers/hosted_mcp.py +43 -0
  383. chrys/app/tui/widgets/chat/renderers/hosted_search.py +167 -0
  384. chrys/app/tui/widgets/chat/renderers/hosted_shell.py +132 -0
  385. chrys/app/tui/widgets/chat/renderers/read_file.py +399 -0
  386. chrys/app/tui/widgets/chat/renderers/search.py +348 -0
  387. chrys/app/tui/widgets/chat/renderers/skill.py +564 -0
  388. chrys/app/tui/widgets/chat/renderers/sleep.py +287 -0
  389. chrys/app/tui/widgets/chat/renderers/sub_agent.py +1385 -0
  390. chrys/app/tui/widgets/chat/renderers/todo.py +114 -0
  391. chrys/app/tui/widgets/chat/renderers/web.py +69 -0
  392. chrys/app/tui/widgets/chat/replay.py +1605 -0
  393. chrys/app/tui/widgets/chat/replay_mount.py +322 -0
  394. chrys/app/tui/widgets/chat/scroll_controller.py +579 -0
  395. chrys/app/tui/widgets/chat/selection_controller.py +435 -0
  396. chrys/app/tui/widgets/chat/session_json.py +508 -0
  397. chrys/app/tui/widgets/chat/toc_model.py +156 -0
  398. chrys/app/tui/widgets/chat/tool_call.py +2478 -0
  399. chrys/app/tui/widgets/chat/tool_registry.py +753 -0
  400. chrys/app/tui/widgets/chat/tool_renderers.py +247 -0
  401. chrys/app/tui/widgets/chat/tool_view_builders.py +260 -0
  402. chrys/app/tui/widgets/chat/transcript_reader.py +57 -0
  403. chrys/app/tui/widgets/checkbox.py +24 -0
  404. chrys/app/tui/widgets/chrome/__init__.py +3 -0
  405. chrys/app/tui/widgets/chrome/app_header.py +283 -0
  406. chrys/app/tui/widgets/chrome/commands.py +95 -0
  407. chrys/app/tui/widgets/chrome/file_index.py +68 -0
  408. chrys/app/tui/widgets/chrome/file_scanner.py +670 -0
  409. chrys/app/tui/widgets/chrome/footer.py +284 -0
  410. chrys/app/tui/widgets/chrome/image_paste.py +351 -0
  411. chrys/app/tui/widgets/chrome/input_bar.py +1299 -0
  412. chrys/app/tui/widgets/chrome/status_bar.py +911 -0
  413. chrys/app/tui/widgets/chrome/suggestion_list.py +652 -0
  414. chrys/app/tui/widgets/click_affordance.py +24 -0
  415. chrys/app/tui/widgets/color_picker/__init__.py +254 -0
  416. chrys/app/tui/widgets/color_picker/controls.py +171 -0
  417. chrys/app/tui/widgets/color_picker/model.py +89 -0
  418. chrys/app/tui/widgets/dialog_buttons.py +58 -0
  419. chrys/app/tui/widgets/dialog_scroll.py +24 -0
  420. chrys/app/tui/widgets/diff_view/__init__.py +20 -0
  421. chrys/app/tui/widgets/diff_view/cells.py +59 -0
  422. chrys/app/tui/widgets/diff_view/code.py +280 -0
  423. chrys/app/tui/widgets/diff_view/compute.py +286 -0
  424. chrys/app/tui/widgets/diff_view/gutter.py +161 -0
  425. chrys/app/tui/widgets/diff_view/inline.py +77 -0
  426. chrys/app/tui/widgets/diff_view/palette.py +87 -0
  427. chrys/app/tui/widgets/diff_view/protocols.py +24 -0
  428. chrys/app/tui/widgets/diff_view/rows.py +138 -0
  429. chrys/app/tui/widgets/diff_view/unified.py +267 -0
  430. chrys/app/tui/widgets/diff_view/widget.py +209 -0
  431. chrys/app/tui/widgets/editor/__init__.py +79 -0
  432. chrys/app/tui/widgets/editor/coordinates.py +30 -0
  433. chrys/app/tui/widgets/editor/highlighter.py +139 -0
  434. chrys/app/tui/widgets/editor/keymaps.py +357 -0
  435. chrys/app/tui/widgets/editor/types.py +216 -0
  436. chrys/app/tui/widgets/editor/vim.py +1195 -0
  437. chrys/app/tui/widgets/editor/widget.py +401 -0
  438. chrys/app/tui/widgets/file_preview.py +58 -0
  439. chrys/app/tui/widgets/hatch.py +138 -0
  440. chrys/app/tui/widgets/input.py +66 -0
  441. chrys/app/tui/widgets/loading.py +125 -0
  442. chrys/app/tui/widgets/markdown/__init__.py +25 -0
  443. chrys/app/tui/widgets/markdown/_utils.py +21 -0
  444. chrys/app/tui/widgets/markdown/anchors.py +71 -0
  445. chrys/app/tui/widgets/markdown/blocks.py +115 -0
  446. chrys/app/tui/widgets/markdown/copyable.py +163 -0
  447. chrys/app/tui/widgets/markdown/diagram/__init__.py +35 -0
  448. chrys/app/tui/widgets/markdown/diagram/canvas.py +409 -0
  449. chrys/app/tui/widgets/markdown/diagram/charts.py +52 -0
  450. chrys/app/tui/widgets/markdown/diagram/diagnostics.py +101 -0
  451. chrys/app/tui/widgets/markdown/diagram/geometry.py +46 -0
  452. chrys/app/tui/widgets/markdown/diagram/layout.py +494 -0
  453. chrys/app/tui/widgets/markdown/diagram/messages.py +18 -0
  454. chrys/app/tui/widgets/markdown/diagram/model.py +275 -0
  455. chrys/app/tui/widgets/markdown/diagram/parser.py +173 -0
  456. chrys/app/tui/widgets/markdown/diagram/parsers/__init__.py +3 -0
  457. chrys/app/tui/widgets/markdown/diagram/parsers/charts.py +349 -0
  458. chrys/app/tui/widgets/markdown/diagram/parsers/common.py +403 -0
  459. chrys/app/tui/widgets/markdown/diagram/parsers/graphs.py +1072 -0
  460. chrys/app/tui/widgets/markdown/diagram/parsers/planning.py +317 -0
  461. chrys/app/tui/widgets/markdown/diagram/parsers/schedule.py +298 -0
  462. chrys/app/tui/widgets/markdown/diagram/parsers/schemas.py +241 -0
  463. chrys/app/tui/widgets/markdown/diagram/parsers/structure.py +221 -0
  464. chrys/app/tui/widgets/markdown/diagram/presentation.py +32 -0
  465. chrys/app/tui/widgets/markdown/diagram/renderers/__init__.py +3 -0
  466. chrys/app/tui/widgets/markdown/diagram/renderers/charts.py +275 -0
  467. chrys/app/tui/widgets/markdown/diagram/renderers/common.py +73 -0
  468. chrys/app/tui/widgets/markdown/diagram/renderers/planning.py +157 -0
  469. chrys/app/tui/widgets/markdown/diagram/renderers/schedule.py +202 -0
  470. chrys/app/tui/widgets/markdown/diagram/renderers/structure.py +77 -0
  471. chrys/app/tui/widgets/markdown/diagram/renderers/xy.py +385 -0
  472. chrys/app/tui/widgets/markdown/diagram/router.py +651 -0
  473. chrys/app/tui/widgets/markdown/diagram/specs/__init__.py +3 -0
  474. chrys/app/tui/widgets/markdown/diagram/specs/charts.py +94 -0
  475. chrys/app/tui/widgets/markdown/diagram/specs/planning.py +68 -0
  476. chrys/app/tui/widgets/markdown/diagram/specs/schedule.py +65 -0
  477. chrys/app/tui/widgets/markdown/diagram/specs/structure.py +23 -0
  478. chrys/app/tui/widgets/markdown/diagram/viewer.py +92 -0
  479. chrys/app/tui/widgets/markdown/links.py +47 -0
  480. chrys/app/tui/widgets/markdown/math/__init__.py +36 -0
  481. chrys/app/tui/widgets/markdown/math/layout.py +739 -0
  482. chrys/app/tui/widgets/markdown/math/markdown.py +291 -0
  483. chrys/app/tui/widgets/markdown/math/parser.py +325 -0
  484. chrys/app/tui/widgets/markdown/math/symbols.py +325 -0
  485. chrys/app/tui/widgets/markdown/navigator.py +80 -0
  486. chrys/app/tui/widgets/markdown/parser.py +1057 -0
  487. chrys/app/tui/widgets/markdown/stream.py +73 -0
  488. chrys/app/tui/widgets/markdown/toc.py +98 -0
  489. chrys/app/tui/widgets/markdown/viewer.py +146 -0
  490. chrys/app/tui/widgets/markdown/widget.py +2046 -0
  491. chrys/app/tui/widgets/marquee.py +101 -0
  492. chrys/app/tui/widgets/option_menu.py +82 -0
  493. chrys/app/tui/widgets/page_navigator.py +118 -0
  494. chrys/app/tui/widgets/select.py +196 -0
  495. chrys/app/tui/widgets/selection.py +59 -0
  496. chrys/app/tui/widgets/sidebar/__init__.py +3 -0
  497. chrys/app/tui/widgets/sidebar/buddy.py +367 -0
  498. chrys/app/tui/widgets/sidebar/context.py +482 -0
  499. chrys/app/tui/widgets/sidebar/debug.py +195 -0
  500. chrys/app/tui/widgets/sidebar/empty_state.py +11 -0
  501. chrys/app/tui/widgets/sidebar/panel.py +198 -0
  502. chrys/app/tui/widgets/sidebar/tasks.py +198 -0
  503. chrys/app/tui/widgets/sidebar/toc.py +166 -0
  504. chrys/app/tui/widgets/sidebar/toc_types.py +30 -0
  505. chrys/app/tui/widgets/syntax_theme.py +85 -0
  506. chrys/app/tui/widgets/text_area.py +258 -0
  507. chrys/app/tui/widgets/trajectory/__init__.py +8 -0
  508. chrys/app/tui/widgets/trajectory/chartkit.py +264 -0
  509. chrys/app/tui/widgets/trajectory/insights.py +1266 -0
  510. chrys/app/tui/widgets/trajectory/overview.py +1101 -0
  511. chrys/app/tui/widgets/trajectory/panel.py +983 -0
  512. chrys/app/tui/widgets/trajectory/presentation.py +311 -0
  513. chrys/app/tui/widgets/trajectory/session_info.py +124 -0
  514. chrys/app/tui/widgets/trajectory/text_view.py +124 -0
  515. chrys/app/tui/widgets/trajectory/timeline.py +380 -0
  516. chrys/app/tui/widgets/welcome.py +126 -0
  517. chrys/app/tui/widgets/workflow/__init__.py +5 -0
  518. chrys/app/tui/widgets/workflow/edges.py +89 -0
  519. chrys/app/tui/widgets/workflow/graph.py +869 -0
  520. chrys/app/tui/widgets/workflow/info.py +310 -0
  521. chrys/app/tui/widgets/workflow/node_view.py +27 -0
  522. chrys/app/tui/widgets/workflow/output.py +225 -0
  523. chrys/app/tui/widgets/workflow/panel.py +658 -0
  524. chrys/app/tui/widgets/workflow/projector.py +324 -0
  525. chrys/app/tui/widgets/workflow/records.py +69 -0
  526. chrys/app/tui/widgets/workflow/scrollbar.py +82 -0
  527. chrys/app/tui/widgets/workflow/selection.py +151 -0
  528. chrys/app/tui/widgets/workflow/source.py +65 -0
  529. chrys/app/tui/widgets/workflow/text.py +257 -0
  530. chrys/app/tui/widgets/workflow/values.py +317 -0
  531. chrys/foundation/__init__.py +0 -0
  532. chrys/foundation/branding.py +15 -0
  533. chrys/foundation/config/__init__.py +7 -0
  534. chrys/foundation/config/coercion.py +374 -0
  535. chrys/foundation/config/context.py +34 -0
  536. chrys/foundation/config/env_file.py +141 -0
  537. chrys/foundation/config/env_layers.py +370 -0
  538. chrys/foundation/config/migrations.py +521 -0
  539. chrys/foundation/config/notification_events.py +22 -0
  540. chrys/foundation/config/process_settings.py +332 -0
  541. chrys/foundation/config/runtime_pointer.py +133 -0
  542. chrys/foundation/config/settings.py +1952 -0
  543. chrys/foundation/config/settings_store.py +996 -0
  544. chrys/foundation/config/spec.py +396 -0
  545. chrys/foundation/config/user_settings.py +140 -0
  546. chrys/foundation/config/warnings.py +262 -0
  547. chrys/foundation/config/web_values.py +135 -0
  548. chrys/foundation/config/yaml_store.py +487 -0
  549. chrys/foundation/errors/__init__.py +68 -0
  550. chrys/foundation/errors/_legacy.py +117 -0
  551. chrys/foundation/errors/_text.py +13 -0
  552. chrys/foundation/errors/_walk.py +85 -0
  553. chrys/foundation/errors/classify.py +278 -0
  554. chrys/foundation/errors/display.py +274 -0
  555. chrys/foundation/errors/formatting.py +283 -0
  556. chrys/foundation/errors/kinds.py +67 -0
  557. chrys/foundation/errors/network.py +497 -0
  558. chrys/foundation/errors/provider.py +445 -0
  559. chrys/foundation/errors/route.py +85 -0
  560. chrys/foundation/events/__init__.py +8 -0
  561. chrys/foundation/events/bus.py +143 -0
  562. chrys/foundation/events/types.py +1629 -0
  563. chrys/foundation/events/workflow.py +38 -0
  564. chrys/foundation/hosted_tools.py +142 -0
  565. chrys/foundation/i18n/__init__.py +32 -0
  566. chrys/foundation/i18n/_catalogs/zh-Hans/LC_MESSAGES/chrys.mo +0 -0
  567. chrys/foundation/i18n/catalogs.py +42 -0
  568. chrys/foundation/i18n/formatting.py +202 -0
  569. chrys/foundation/i18n/locale.py +92 -0
  570. chrys/foundation/i18n/localizer.py +187 -0
  571. chrys/foundation/i18n/messages.py +268 -0
  572. chrys/foundation/io/__init__.py +3 -0
  573. chrys/foundation/io/result_content.py +237 -0
  574. chrys/foundation/models/__init__.py +3 -0
  575. chrys/foundation/models/approval_reuse.py +23 -0
  576. chrys/foundation/models/ask_user.py +468 -0
  577. chrys/foundation/models/execution.py +18 -0
  578. chrys/foundation/models/history_markers.py +115 -0
  579. chrys/foundation/models/invocations.py +63 -0
  580. chrys/foundation/models/mutation_scope.py +28 -0
  581. chrys/foundation/models/session_env.py +87 -0
  582. chrys/foundation/models/session_surface.py +29 -0
  583. chrys/foundation/models/todos.py +74 -0
  584. chrys/foundation/models/turns.py +125 -0
  585. chrys/foundation/models/workflow_session.py +89 -0
  586. chrys/foundation/models/workspace.py +59 -0
  587. chrys/foundation/net/__init__.py +3 -0
  588. chrys/foundation/net/address_class.py +57 -0
  589. chrys/foundation/net/route_probe.py +94 -0
  590. chrys/foundation/net/url.py +107 -0
  591. chrys/foundation/observability/__init__.py +3 -0
  592. chrys/foundation/observability/exporters.py +174 -0
  593. chrys/foundation/observability/gate.py +31 -0
  594. chrys/foundation/observability/setup.py +497 -0
  595. chrys/foundation/observability/sink.py +228 -0
  596. chrys/foundation/patches/__init__.py +19 -0
  597. chrys/foundation/patches/mdurl_cache.py +59 -0
  598. chrys/foundation/patches/patcher.py +287 -0
  599. chrys/foundation/patches/staged_members.py +205 -0
  600. chrys/foundation/patches/textual_block_border.py +105 -0
  601. chrys/foundation/patches/textual_button_ansi.py +65 -0
  602. chrys/foundation/patches/textual_button_ansi_old.txt +68 -0
  603. chrys/foundation/patches/textual_callback_cache.py +248 -0
  604. chrys/foundation/patches/textual_callback_dispatch.py +109 -0
  605. chrys/foundation/patches/textual_compositor_cjk.py +566 -0
  606. chrys/foundation/patches/textual_dispatch_cache.py +150 -0
  607. chrys/foundation/patches/textual_ime_cursor_anchor.py +92 -0
  608. chrys/foundation/patches/textual_kitty_keyboard.py +268 -0
  609. chrys/foundation/patches/textual_lru_acyclic.py +241 -0
  610. chrys/foundation/patches/textual_message_pump.py +136 -0
  611. chrys/foundation/patches/textual_node_diet.py +875 -0
  612. chrys/foundation/patches/textual_one_shot_timer.py +48 -0
  613. chrys/foundation/patches/textual_option_list.py +90 -0
  614. chrys/foundation/patches/textual_precompose.py +89 -0
  615. chrys/foundation/patches/textual_pruned_tabs.py +69 -0
  616. chrys/foundation/patches/textual_reflow_reuse.py +1753 -0
  617. chrys/foundation/patches/textual_removed_node_caches.py +86 -0
  618. chrys/foundation/patches/textual_removed_screen_callbacks.py +55 -0
  619. chrys/foundation/patches/textual_selection_extract.py +48 -0
  620. chrys/foundation/patches/textual_strip_cycles.py +119 -0
  621. chrys/foundation/patches/textual_tab_selection.py +1611 -0
  622. chrys/foundation/patches/textual_timer_skip.py +70 -0
  623. chrys/foundation/patches/textual_utf8_decoder.py +106 -0
  624. chrys/foundation/patches/textual_win_sleep.py +167 -0
  625. chrys/foundation/patches/watchdog_fsevents.py +70 -0
  626. chrys/foundation/patches/watchdog_windows.py +52 -0
  627. chrys/foundation/platform/__init__.py +556 -0
  628. chrys/foundation/platform/c_api.py +32 -0
  629. chrys/foundation/platform/child_reap.py +107 -0
  630. chrys/foundation/platform/command_line.py +95 -0
  631. chrys/foundation/platform/files.py +1470 -0
  632. chrys/foundation/platform/output_capture.py +113 -0
  633. chrys/foundation/platform/paths.py +193 -0
  634. chrys/foundation/platform/process.py +1468 -0
  635. chrys/foundation/platform/pty_output.py +19 -0
  636. chrys/foundation/platform/runtime_paths.py +281 -0
  637. chrys/foundation/platform/win_console.py +129 -0
  638. chrys/foundation/reasoning_origin.py +67 -0
  639. chrys/foundation/recovery.py +16 -0
  640. chrys/foundation/retry.py +278 -0
  641. chrys/foundation/text/__init__.py +3 -0
  642. chrys/foundation/text/encoding.py +603 -0
  643. chrys/foundation/text/images.py +304 -0
  644. chrys/foundation/text/lines.py +24 -0
  645. chrys/foundation/text/mentions.py +90 -0
  646. chrys/foundation/text/model_json.py +25 -0
  647. chrys/foundation/text/reading_order.py +20 -0
  648. chrys/foundation/text/tokenizer.py +25 -0
  649. chrys/foundation/text/tool_output.py +287 -0
  650. chrys/foundation/text/yaml_io.py +62 -0
  651. chrys/foundation/tool_call_context.py +202 -0
  652. chrys/foundation/tool_execution_stamp.py +184 -0
  653. chrys/foundation/tool_invocation_order.py +48 -0
  654. chrys/foundation/tool_kinds.py +102 -0
  655. chrys/foundation/tool_result_metadata.py +287 -0
  656. chrys/foundation/trajectory/__init__.py +10 -0
  657. chrys/foundation/trajectory/context.py +481 -0
  658. chrys/foundation/trajectory/envelope.py +571 -0
  659. chrys/foundation/trajectory/event_types.py +294 -0
  660. chrys/foundation/trajectory/finalizers.py +46 -0
  661. chrys/foundation/trajectory/fingerprint.py +62 -0
  662. chrys/foundation/trajectory/ids.py +155 -0
  663. chrys/foundation/trajectory/keys.py +99 -0
  664. chrys/foundation/trajectory/lease.py +173 -0
  665. chrys/foundation/trajectory/metadata.py +72 -0
  666. chrys/foundation/trajectory/reader.py +271 -0
  667. chrys/foundation/trajectory/recovery.py +225 -0
  668. chrys/foundation/trajectory/revisions.py +152 -0
  669. chrys/foundation/trajectory/segments.py +225 -0
  670. chrys/foundation/trajectory/tools.py +117 -0
  671. chrys/foundation/trajectory/usage.py +151 -0
  672. chrys/foundation/trajectory/writer.py +972 -0
  673. chrys/foundation/trajectory_timing.py +97 -0
  674. chrys/foundation/util/__init__.py +3 -0
  675. chrys/foundation/util/async_tasks.py +29 -0
  676. chrys/foundation/util/chrys_headers.py +23 -0
  677. chrys/foundation/util/env_templates.py +104 -0
  678. chrys/foundation/util/filenames.py +96 -0
  679. chrys/foundation/util/header_charset.py +138 -0
  680. chrys/foundation/util/httpx_helpers.py +12 -0
  681. chrys/foundation/util/lock.py +236 -0
  682. chrys/foundation/util/once_close.py +46 -0
  683. chrys/foundation/util/session_ids.py +29 -0
  684. chrys/foundation/util/shell_tokens.py +88 -0
  685. chrys/foundation/util/sub_agent_context.py +38 -0
  686. chrys/foundation/util/time.py +35 -0
  687. chrys/foundation/util/unicode_scalars.py +36 -0
  688. chrys/foundation/vendor/__init__.py +43 -0
  689. chrys/foundation/vendor/ripgrep/rg-aarch64-apple-darwin +0 -0
  690. chrys/foundation/vendor/ripgrep/rg-aarch64-pc-windows-msvc.exe +0 -0
  691. chrys/foundation/vendor/ripgrep/rg-aarch64-unknown-linux-gnu +0 -0
  692. chrys/foundation/vendor/ripgrep/rg-x86_64-apple-darwin +0 -0
  693. chrys/foundation/vendor/ripgrep/rg-x86_64-pc-windows-msvc.exe +0 -0
  694. chrys/foundation/vendor/ripgrep/rg-x86_64-unknown-linux-musl +0 -0
  695. chrys/kernel/__init__.py +256 -0
  696. chrys/kernel/_content.py +1866 -0
  697. chrys/kernel/_loop_recorder.py +631 -0
  698. chrys/kernel/_null_overlay.py +1026 -0
  699. chrys/kernel/_result_ceiling.py +216 -0
  700. chrys/kernel/_serialization.py +431 -0
  701. chrys/kernel/_tool_arg_errors.py +1629 -0
  702. chrys/kernel/_tool_execution.py +1172 -0
  703. chrys/kernel/_tool_expansion.py +26 -0
  704. chrys/kernel/_types.py +2598 -0
  705. chrys/kernel/agent.py +994 -0
  706. chrys/kernel/client.py +1084 -0
  707. chrys/kernel/compaction.py +1315 -0
  708. chrys/kernel/exceptions.py +211 -0
  709. chrys/kernel/exchanges.py +683 -0
  710. chrys/kernel/identity.py +95 -0
  711. chrys/kernel/images.py +36 -0
  712. chrys/kernel/instrumentation.py +1618 -0
  713. chrys/kernel/loop.py +2308 -0
  714. chrys/kernel/middleware.py +616 -0
  715. chrys/kernel/sessions.py +604 -0
  716. chrys/kernel/tools.py +1061 -0
  717. chrys/kernel/types.py +126 -0
  718. chrys/orchestration/__init__.py +3 -0
  719. chrys/orchestration/engine/__init__.py +3 -0
  720. chrys/orchestration/engine/assembly.py +236 -0
  721. chrys/orchestration/engine/build/__init__.py +3 -0
  722. chrys/orchestration/engine/build/builder.py +1061 -0
  723. chrys/orchestration/engine/build/construction.py +408 -0
  724. chrys/orchestration/engine/build/loaded.py +139 -0
  725. chrys/orchestration/engine/engine.py +789 -0
  726. chrys/orchestration/engine/execution.py +771 -0
  727. chrys/orchestration/engine/loader.py +865 -0
  728. chrys/orchestration/engine/rollback.py +918 -0
  729. chrys/orchestration/engine/run/__init__.py +3 -0
  730. chrys/orchestration/engine/run/active_injection.py +419 -0
  731. chrys/orchestration/engine/run/attachments.py +519 -0
  732. chrys/orchestration/engine/run/bindings.py +1095 -0
  733. chrys/orchestration/engine/run/coordinator.py +1062 -0
  734. chrys/orchestration/engine/run/finalizer.py +417 -0
  735. chrys/orchestration/engine/run/input_refs.py +60 -0
  736. chrys/orchestration/engine/run/prompt_content.py +457 -0
  737. chrys/orchestration/engine/run/resume.py +299 -0
  738. chrys/orchestration/engine/run/retry.py +948 -0
  739. chrys/orchestration/engine/run/runner.py +625 -0
  740. chrys/orchestration/engine/run/runtime_skills.py +146 -0
  741. chrys/orchestration/engine/run/sub_agent_coordination.py +126 -0
  742. chrys/orchestration/engine/run/turn_hooks.py +258 -0
  743. chrys/orchestration/engine/run/turn_state.py +149 -0
  744. chrys/orchestration/engine/run/working_dir.py +50 -0
  745. chrys/orchestration/engine/session_lifecycle.py +2013 -0
  746. chrys/orchestration/engine/state/__init__.py +3 -0
  747. chrys/orchestration/engine/state/active_session.py +183 -0
  748. chrys/orchestration/engine/state/controls.py +639 -0
  749. chrys/orchestration/engine/state/current_agent.py +26 -0
  750. chrys/orchestration/engine/state/lifecycle_permits.py +395 -0
  751. chrys/orchestration/engine/state/machine.py +193 -0
  752. chrys/orchestration/engine/state/session_writer.py +434 -0
  753. chrys/orchestration/engine/trajectory.py +714 -0
  754. chrys/orchestration/engine/usage.py +118 -0
  755. chrys/orchestration/invoker/__init__.py +3 -0
  756. chrys/orchestration/invoker/acp.py +727 -0
  757. chrys/orchestration/invoker/acp_protocol.py +1115 -0
  758. chrys/orchestration/invoker/acp_spec.py +79 -0
  759. chrys/orchestration/invoker/attempts.py +994 -0
  760. chrys/orchestration/invoker/child_compaction.py +131 -0
  761. chrys/orchestration/invoker/child_history.py +99 -0
  762. chrys/orchestration/invoker/contracts.py +253 -0
  763. chrys/orchestration/invoker/evidence.py +94 -0
  764. chrys/orchestration/invoker/kernel.py +343 -0
  765. chrys/orchestration/invoker/origin.py +79 -0
  766. chrys/orchestration/invoker/resources.py +343 -0
  767. chrys/orchestration/invoker/runtime.py +299 -0
  768. chrys/orchestration/invoker/usage.py +80 -0
  769. chrys/orchestration/session_hooks.py +117 -0
  770. chrys/orchestration/session_host.py +1023 -0
  771. chrys/orchestration/session_resources.py +95 -0
  772. chrys/orchestration/session_usage.py +219 -0
  773. chrys/orchestration/startup.py +255 -0
  774. chrys/orchestration/sub_agents/__init__.py +3 -0
  775. chrys/orchestration/sub_agents/acp_policy.py +269 -0
  776. chrys/orchestration/sub_agents/kernel_policy.py +848 -0
  777. chrys/orchestration/sub_agents/registration.py +44 -0
  778. chrys/orchestration/sub_agents/shell.py +337 -0
  779. chrys/orchestration/sub_agents/tools.py +2228 -0
  780. chrys/orchestration/workflows/__init__.py +3 -0
  781. chrys/orchestration/workflows/agent_archive.py +156 -0
  782. chrys/orchestration/workflows/agent_node.py +894 -0
  783. chrys/orchestration/workflows/agent_node_build.py +687 -0
  784. chrys/orchestration/workflows/catalog.py +332 -0
  785. chrys/orchestration/workflows/coordinator.py +771 -0
  786. chrys/orchestration/workflows/hooks.py +176 -0
  787. chrys/orchestration/workflows/preview.py +322 -0
  788. chrys/orchestration/workflows/rollback.py +151 -0
  789. chrys/orchestration/workflows/runner.py +986 -0
  790. chrys/orchestration/workflows/session.py +390 -0
  791. chrys/orchestration/workflows/settings.py +97 -0
  792. chrys/orchestration/workflows/validation.py +674 -0
  793. chrys/orchestration/workflows/worker_client.py +1002 -0
  794. chrys/service/__init__.py +3 -0
  795. chrys/service/acp_client/__init__.py +65 -0
  796. chrys/service/acp_client/_transport.py +922 -0
  797. chrys/service/acp_client/client.py +1311 -0
  798. chrys/service/acp_client/errors.py +224 -0
  799. chrys/service/acp_client/protocol.py +220 -0
  800. chrys/service/acp_client/spawn.py +239 -0
  801. chrys/service/acp_client/spec.py +100 -0
  802. chrys/service/agent_middleware/__init__.py +60 -0
  803. chrys/service/agent_middleware/_metadata_keys.py +52 -0
  804. chrys/service/agent_middleware/control/__init__.py +3 -0
  805. chrys/service/agent_middleware/control/approval.py +769 -0
  806. chrys/service/agent_middleware/control/approval_hooks.py +62 -0
  807. chrys/service/agent_middleware/control/ask_user.py +207 -0
  808. chrys/service/agent_middleware/control/interrupt.py +50 -0
  809. chrys/service/agent_middleware/control/sleep.py +118 -0
  810. chrys/service/agent_middleware/control/todo.py +117 -0
  811. chrys/service/agent_middleware/events/__init__.py +3 -0
  812. chrys/service/agent_middleware/events/hook_dispatch.py +250 -0
  813. chrys/service/agent_middleware/events/hosted_tools.py +1762 -0
  814. chrys/service/agent_middleware/events/intermediate_text.py +128 -0
  815. chrys/service/agent_middleware/events/rejection_metadata.py +50 -0
  816. chrys/service/agent_middleware/events/result_persistence.py +98 -0
  817. chrys/service/agent_middleware/events/sub_agent_events.py +951 -0
  818. chrys/service/agent_middleware/events/tool_error_text.py +22 -0
  819. chrys/service/agent_middleware/events/tool_events.py +779 -0
  820. chrys/service/agent_middleware/injection.py +510 -0
  821. chrys/service/agent_middleware/reminders/__init__.py +91 -0
  822. chrys/service/agent_middleware/reminders/archive_pointer.py +154 -0
  823. chrys/service/agent_middleware/reminders/base.py +25 -0
  824. chrys/service/agent_middleware/reminders/context_usage.py +74 -0
  825. chrys/service/agent_middleware/reminders/file_change.py +63 -0
  826. chrys/service/agent_middleware/reminders/mcp.py +39 -0
  827. chrys/service/agent_middleware/reminders/profile_switch.py +106 -0
  828. chrys/service/agent_middleware/reminders/runtime_env.py +190 -0
  829. chrys/service/agent_middleware/reminders/skills.py +44 -0
  830. chrys/service/agent_middleware/reminders/sub_agents.py +35 -0
  831. chrys/service/agent_middleware/reminders/todo.py +35 -0
  832. chrys/service/agent_middleware/reminders/turn_line.py +48 -0
  833. chrys/service/agent_middleware/response_validation.py +1380 -0
  834. chrys/service/agent_middleware/system_reminder.py +1107 -0
  835. chrys/service/agent_middleware/validators.py +396 -0
  836. chrys/service/analytics/__init__.py +124 -0
  837. chrys/service/analytics/_actions.py +896 -0
  838. chrys/service/analytics/_context_evidence.py +357 -0
  839. chrys/service/analytics/_critical_path.py +179 -0
  840. chrys/service/analytics/_facts.py +919 -0
  841. chrys/service/analytics/_insights.py +769 -0
  842. chrys/service/analytics/_metric_ops.py +83 -0
  843. chrys/service/analytics/_session_projection.py +460 -0
  844. chrys/service/analytics/_timeline.py +434 -0
  845. chrys/service/analytics/_turn_graph.py +1237 -0
  846. chrys/service/analytics/_turns.py +1377 -0
  847. chrys/service/analytics/_workflows.py +171 -0
  848. chrys/service/analytics/aggregation.py +1474 -0
  849. chrys/service/analytics/classification.py +128 -0
  850. chrys/service/analytics/export.py +803 -0
  851. chrys/service/analytics/findings.py +282 -0
  852. chrys/service/analytics/math.py +79 -0
  853. chrys/service/analytics/model.py +886 -0
  854. chrys/service/analytics/reader.py +321 -0
  855. chrys/service/approval/__init__.py +3 -0
  856. chrys/service/approval/arbitration.py +102 -0
  857. chrys/service/approval/command_identity.py +109 -0
  858. chrys/service/approval/correlation.py +57 -0
  859. chrys/service/approval/grant_store.py +108 -0
  860. chrys/service/approval/judge.py +589 -0
  861. chrys/service/approval/level.py +15 -0
  862. chrys/service/approval/policy.py +209 -0
  863. chrys/service/approval/reuse.py +223 -0
  864. chrys/service/approval/reuse_binding.py +133 -0
  865. chrys/service/approval/safety_classifier.py +536 -0
  866. chrys/service/approval/turn_context.py +49 -0
  867. chrys/service/context/__init__.py +3 -0
  868. chrys/service/context/compaction/__init__.py +38 -0
  869. chrys/service/context/compaction/breaker.py +156 -0
  870. chrys/service/context/compaction/budgets.py +93 -0
  871. chrys/service/context/compaction/calibration.py +77 -0
  872. chrys/service/context/compaction/compression.py +690 -0
  873. chrys/service/context/compaction/current_turn_drop.py +458 -0
  874. chrys/service/context/compaction/events.py +201 -0
  875. chrys/service/context/compaction/exclusions.py +261 -0
  876. chrys/service/context/compaction/groups.py +361 -0
  877. chrys/service/context/compaction/last_words.py +1996 -0
  878. chrys/service/context/compaction/last_words_state.py +752 -0
  879. chrys/service/context/compaction/scoped.py +472 -0
  880. chrys/service/context/compaction/spill.py +1947 -0
  881. chrys/service/context/compaction/strategy.py +1116 -0
  882. chrys/service/context/compaction/summaries.py +319 -0
  883. chrys/service/context/compaction/turns.py +375 -0
  884. chrys/service/context/manager.py +174 -0
  885. chrys/service/context/memory_loader.py +792 -0
  886. chrys/service/context/middleware/__init__.py +3 -0
  887. chrys/service/context/middleware/usage.py +332 -0
  888. chrys/service/context/providers/__init__.py +3 -0
  889. chrys/service/context/providers/context_management.py +432 -0
  890. chrys/service/context/providers/history.py +647 -0
  891. chrys/service/context/providers/memory.py +50 -0
  892. chrys/service/context/tool_content.py +22 -0
  893. chrys/service/hooks/__init__.py +37 -0
  894. chrys/service/hooks/detached_worker.py +118 -0
  895. chrys/service/hooks/docs/README.md +14 -0
  896. chrys/service/hooks/docs/authoring.md +684 -0
  897. chrys/service/hooks/docs/configuration.md +499 -0
  898. chrys/service/hooks/docs/design.md +359 -0
  899. chrys/service/hooks/docs/project-hooks.md +348 -0
  900. chrys/service/hooks/events.py +157 -0
  901. chrys/service/hooks/loader.py +665 -0
  902. chrys/service/hooks/manager.py +807 -0
  903. chrys/service/hooks/matcher.py +111 -0
  904. chrys/service/hooks/outbox.py +294 -0
  905. chrys/service/hooks/runner.py +572 -0
  906. chrys/service/hooks/schema.py +407 -0
  907. chrys/service/llm/__init__.py +7 -0
  908. chrys/service/llm/_structured_outputs.py +192 -0
  909. chrys/service/llm/anthropic_messages/__init__.py +9 -0
  910. chrys/service/llm/anthropic_messages/client.py +254 -0
  911. chrys/service/llm/anthropic_messages/decode.py +331 -0
  912. chrys/service/llm/anthropic_messages/history.py +279 -0
  913. chrys/service/llm/anthropic_messages/request.py +323 -0
  914. chrys/service/llm/anthropic_messages/server_tools.py +319 -0
  915. chrys/service/llm/anthropic_messages/stream.py +297 -0
  916. chrys/service/llm/anthropic_messages/thinking_binding.py +156 -0
  917. chrys/service/llm/chat_completions/__init__.py +9 -0
  918. chrys/service/llm/chat_completions/client.py +369 -0
  919. chrys/service/llm/chat_completions/decode.py +338 -0
  920. chrys/service/llm/chat_completions/history.py +657 -0
  921. chrys/service/llm/chat_completions/reasoning.py +244 -0
  922. chrys/service/llm/chat_completions/request.py +192 -0
  923. chrys/service/llm/chat_completions/stream.py +546 -0
  924. chrys/service/llm/chat_completions/validation.py +308 -0
  925. chrys/service/llm/clients.py +613 -0
  926. chrys/service/llm/images.py +65 -0
  927. chrys/service/llm/mock.py +413 -0
  928. chrys/service/llm/observer.py +446 -0
  929. chrys/service/llm/one_shot.py +106 -0
  930. chrys/service/llm/openai_exceptions.py +93 -0
  931. chrys/service/llm/openai_responses/__init__.py +10 -0
  932. chrys/service/llm/openai_responses/client.py +323 -0
  933. chrys/service/llm/openai_responses/decode.py +432 -0
  934. chrys/service/llm/openai_responses/history.py +519 -0
  935. chrys/service/llm/openai_responses/hosted.py +625 -0
  936. chrys/service/llm/openai_responses/replay.py +629 -0
  937. chrys/service/llm/openai_responses/request.py +342 -0
  938. chrys/service/llm/openai_responses/stream.py +847 -0
  939. chrys/service/llm/openai_timestamps.py +57 -0
  940. chrys/service/llm/providers.py +107 -0
  941. chrys/service/llm/proxy_route.py +54 -0
  942. chrys/service/llm/raw_http_log.py +309 -0
  943. chrys/service/llm/route_facts.py +63 -0
  944. chrys/service/llm/route_sessions.py +49 -0
  945. chrys/service/llm/sdk_anthropic.py +18 -0
  946. chrys/service/llm/sdk_headers.py +47 -0
  947. chrys/service/llm/sdk_openai.py +18 -0
  948. chrys/service/llm/sdk_retry.py +59 -0
  949. chrys/service/llm/wire_client.py +246 -0
  950. chrys/service/mcp/__init__.py +3 -0
  951. chrys/service/mcp/_connection.py +235 -0
  952. chrys/service/mcp/_http_transport.py +350 -0
  953. chrys/service/mcp/_progressive.py +459 -0
  954. chrys/service/mcp/_stdio_transport.py +614 -0
  955. chrys/service/mcp/_tool_mixins.py +96 -0
  956. chrys/service/mcp/adapter.py +1031 -0
  957. chrys/service/mcp/cache.py +476 -0
  958. chrys/service/mcp/content.py +32 -0
  959. chrys/service/mcp/errors.py +169 -0
  960. chrys/service/mcp/owned.py +1330 -0
  961. chrys/service/mcp/result_limits.py +168 -0
  962. chrys/service/mcp/thinking_warning.py +95 -0
  963. chrys/service/mcp/validation.py +74 -0
  964. chrys/service/mutations/__init__.py +84 -0
  965. chrys/service/mutations/coordination.py +894 -0
  966. chrys/service/mutations/detector.py +458 -0
  967. chrys/service/mutations/git_calibrator.py +397 -0
  968. chrys/service/mutations/git_state.py +647 -0
  969. chrys/service/mutations/pipeline.py +779 -0
  970. chrys/service/mutations/scanner.py +466 -0
  971. chrys/service/mutations/snapshot_files.py +233 -0
  972. chrys/service/mutations/store.py +625 -0
  973. chrys/service/mutations/tool_names.py +15 -0
  974. chrys/service/mutations/trace.py +246 -0
  975. chrys/service/mutations/tracker.py +1289 -0
  976. chrys/service/mutations/types.py +559 -0
  977. chrys/service/mutations/workspace_changes.py +1583 -0
  978. chrys/service/profiles/__init__.py +2 -0
  979. chrys/service/profiles/agents/__init__.py +3 -0
  980. chrys/service/profiles/agents/builtins/Code.yaml +199 -0
  981. chrys/service/profiles/agents/builtins/Explore.yaml +62 -0
  982. chrys/service/profiles/agents/builtins/General.yaml +114 -0
  983. chrys/service/profiles/agents/builtins/QA.yaml +128 -0
  984. chrys/service/profiles/agents/loader.py +808 -0
  985. chrys/service/profiles/agents/registry.py +727 -0
  986. chrys/service/profiles/agents/schema.py +371 -0
  987. chrys/service/profiles/agents/serializer.py +196 -0
  988. chrys/service/profiles/coercion.py +22 -0
  989. chrys/service/profiles/models/__init__.py +3 -0
  990. chrys/service/profiles/models/env_bridge.py +157 -0
  991. chrys/service/profiles/models/loader.py +282 -0
  992. chrys/service/profiles/models/options.py +438 -0
  993. chrys/service/profiles/models/registry.py +104 -0
  994. chrys/service/profiles/models/resolver.py +286 -0
  995. chrys/service/profiles/models/schema.py +91 -0
  996. chrys/service/profiles/models/serializer.py +76 -0
  997. chrys/service/session/__init__.py +3 -0
  998. chrys/service/session/checkpoint.py +156 -0
  999. chrys/service/session/history.py +1616 -0
  1000. chrys/service/session/message_metadata.py +151 -0
  1001. chrys/service/session/persistence.py +435 -0
  1002. chrys/service/session/runtime_metadata.py +210 -0
  1003. chrys/service/session/sub_agent_logs.py +1069 -0
  1004. chrys/service/session/sub_agent_transcript.py +654 -0
  1005. chrys/service/skills/__init__.py +3 -0
  1006. chrys/service/skills/adapter.py +408 -0
  1007. chrys/service/skills/constants.py +8 -0
  1008. chrys/service/skills/loader.py +575 -0
  1009. chrys/service/skills/model.py +130 -0
  1010. chrys/service/skills/provider.py +841 -0
  1011. chrys/service/skills/runner.py +390 -0
  1012. chrys/service/state/__init__.py +3 -0
  1013. chrys/service/state/_fork.py +710 -0
  1014. chrys/service/state/_session_files.py +175 -0
  1015. chrys/service/state/_session_meta.py +552 -0
  1016. chrys/service/state/locks.py +154 -0
  1017. chrys/service/state/serializers.py +156 -0
  1018. chrys/service/state/session_catalog.py +361 -0
  1019. chrys/service/state/session_listing.py +84 -0
  1020. chrys/service/state/session_migration.py +446 -0
  1021. chrys/service/state/session_mru.py +315 -0
  1022. chrys/service/state/store.py +2132 -0
  1023. chrys/service/state/workflow.py +158 -0
  1024. chrys/service/text_blocks.py +47 -0
  1025. chrys/service/todos/__init__.py +3 -0
  1026. chrys/service/todos/reminder.py +31 -0
  1027. chrys/service/todos/tracker.py +58 -0
  1028. chrys/service/tools/__init__.py +3 -0
  1029. chrys/service/tools/approval_targets.py +92 -0
  1030. chrys/service/tools/builtins/__init__.py +3 -0
  1031. chrys/service/tools/builtins/ask_user.py +326 -0
  1032. chrys/service/tools/builtins/doc_converter/__init__.py +494 -0
  1033. chrys/service/tools/builtins/doc_converter/artifacts.py +392 -0
  1034. chrys/service/tools/builtins/doc_converter/parsers/__init__.py +3 -0
  1035. chrys/service/tools/builtins/doc_converter/parsers/_table.py +34 -0
  1036. chrys/service/tools/builtins/doc_converter/parsers/base.py +101 -0
  1037. chrys/service/tools/builtins/doc_converter/parsers/docx.py +88 -0
  1038. chrys/service/tools/builtins/doc_converter/parsers/pdf.py +144 -0
  1039. chrys/service/tools/builtins/doc_converter/parsers/pptx.py +103 -0
  1040. chrys/service/tools/builtins/doc_converter/parsers/xls.py +32 -0
  1041. chrys/service/tools/builtins/doc_converter/parsers/xlsx.py +51 -0
  1042. chrys/service/tools/builtins/doc_converter/registry.py +55 -0
  1043. chrys/service/tools/builtins/filesystem.py +1071 -0
  1044. chrys/service/tools/builtins/search.py +1265 -0
  1045. chrys/service/tools/builtins/shell.py +967 -0
  1046. chrys/service/tools/builtins/shell_command_filtering/__init__.py +5 -0
  1047. chrys/service/tools/builtins/shell_command_filtering/policy.py +60 -0
  1048. chrys/service/tools/builtins/shell_command_filtering/presets.py +152 -0
  1049. chrys/service/tools/builtins/shell_command_filtering/readonly/__init__.py +358 -0
  1050. chrys/service/tools/builtins/shell_command_filtering/readonly/commands.py +416 -0
  1051. chrys/service/tools/builtins/shell_command_filtering/readonly/git.py +408 -0
  1052. chrys/service/tools/builtins/shell_command_filtering/readonly/syntax.py +87 -0
  1053. chrys/service/tools/builtins/shell_command_filtering/tokenizer.py +214 -0
  1054. chrys/service/tools/builtins/shell_filter.py +24 -0
  1055. chrys/service/tools/builtins/sleep.py +91 -0
  1056. chrys/service/tools/builtins/todo.py +64 -0
  1057. chrys/service/tools/builtins/web/__init__.py +6 -0
  1058. chrys/service/tools/builtins/web/build.py +268 -0
  1059. chrys/service/tools/builtins/web/config.py +338 -0
  1060. chrys/service/tools/builtins/web/credentials.py +37 -0
  1061. chrys/service/tools/builtins/web/fetch/__init__.py +3 -0
  1062. chrys/service/tools/builtins/web/fetch/cache.py +68 -0
  1063. chrys/service/tools/builtins/web/fetch/convert.py +56 -0
  1064. chrys/service/tools/builtins/web/fetch/tool.py +223 -0
  1065. chrys/service/tools/builtins/web/hosted.py +61 -0
  1066. chrys/service/tools/builtins/web/http.py +330 -0
  1067. chrys/service/tools/builtins/web/progress.py +18 -0
  1068. chrys/service/tools/builtins/web/search/__init__.py +3 -0
  1069. chrys/service/tools/builtins/web/search/exa_mcp.py +146 -0
  1070. chrys/service/tools/builtins/web/search/html.py +152 -0
  1071. chrys/service/tools/builtins/web/search/json_api.py +227 -0
  1072. chrys/service/tools/builtins/web/search/providers.py +77 -0
  1073. chrys/service/tools/builtins/web/search/tool.py +218 -0
  1074. chrys/service/tools/builtins/web/search/types.py +28 -0
  1075. chrys/service/tools/builtins/web/tls_identity.py +66 -0
  1076. chrys/service/tools/kinds.py +115 -0
  1077. chrys/service/tools/names.py +47 -0
  1078. chrys/service/tools/registry.py +242 -0
  1079. chrys/service/tools/result_metadata.py +103 -0
  1080. chrys/service/tools/session_artifacts.py +196 -0
  1081. chrys/service/tools/spill.py +218 -0
  1082. chrys/service/tools/workspace_paths.py +81 -0
  1083. chrys/service/trajectory/__init__.py +11 -0
  1084. chrys/service/trajectory/approvals.py +201 -0
  1085. chrys/service/trajectory/compaction.py +420 -0
  1086. chrys/service/trajectory/fork.py +75 -0
  1087. chrys/service/trajectory/hooks.py +217 -0
  1088. chrys/service/trajectory/items.py +41 -0
  1089. chrys/service/trajectory/preparation.py +374 -0
  1090. chrys/service/trajectory/retries.py +95 -0
  1091. chrys/service/trajectory/revisions.py +129 -0
  1092. chrys/service/trajectory/segmented.py +163 -0
  1093. chrys/service/trajectory/session.py +762 -0
  1094. chrys/service/trajectory/state.py +83 -0
  1095. chrys/service/trajectory/sub_agents.py +169 -0
  1096. chrys/service/trajectory/tombstone.py +262 -0
  1097. chrys/service/trajectory/tools.py +323 -0
  1098. chrys/service/trajectory/validation.py +130 -0
  1099. chrys/service/trajectory/waits.py +161 -0
  1100. chrys/service/trajectory/workflow.py +148 -0
  1101. chrys/service/vision.py +128 -0
  1102. chrys/service/workflows/__init__.py +3 -0
  1103. chrys/service/workflows/admission.py +151 -0
  1104. chrys/service/workflows/artifacts.py +109 -0
  1105. chrys/service/workflows/asks.py +130 -0
  1106. chrys/service/workflows/builtins/__init__.py +12 -0
  1107. chrys/service/workflows/builtins/demo-workflow.manifest.json +635 -0
  1108. chrys/service/workflows/builtins/demo-workflow.py +756 -0
  1109. chrys/service/workflows/discovery.py +554 -0
  1110. chrys/service/workflows/environment.py +284 -0
  1111. chrys/service/workflows/graph.py +430 -0
  1112. chrys/service/workflows/history.py +82 -0
  1113. chrys/service/workflows/interpreter.py +107 -0
  1114. chrys/service/workflows/journal.py +334 -0
  1115. chrys/service/workflows/layout.py +56 -0
  1116. chrys/service/workflows/ledger.py +149 -0
  1117. chrys/service/workflows/model_selection.py +18 -0
  1118. chrys/service/workflows/orphans.py +209 -0
  1119. chrys/service/workflows/outcomes.py +46 -0
  1120. chrys/service/workflows/protocol.py +210 -0
  1121. chrys/service/workflows/records.py +142 -0
  1122. chrys/service/workflows/scheduler.py +770 -0
  1123. chrys/service/workflows/sdk/__init__.py +51 -0
  1124. chrys/service/workflows/sdk/_ask.py +167 -0
  1125. chrys/service/workflows/sdk/_builder.py +781 -0
  1126. chrys/service/workflows/sdk/_values.py +92 -0
  1127. chrys/service/workflows/sdk_artifact.py +74 -0
  1128. chrys/service/workflows/store.py +494 -0
  1129. chrys/service/workflows/transcript.py +102 -0
  1130. chrys/service/workflows/values.py +73 -0
  1131. chrys/service/workflows/worker_host.py +1820 -0
  1132. chrys/workflows.py +38 -0
  1133. icode_tui-0.29.1.dist-info/METADATA +104 -0
  1134. icode_tui-0.29.1.dist-info/RECORD +1138 -0
  1135. icode_tui-0.29.1.dist-info/WHEEL +4 -0
  1136. icode_tui-0.29.1.dist-info/entry_points.txt +2 -0
  1137. icode_tui-0.29.1.dist-info/licenses/LICENSE +202 -0
  1138. icode_tui-0.29.1.dist-info/licenses/NOTICE +1955 -0
@@ -0,0 +1,948 @@
1
+ # Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
2
+
3
+ """Retry admission and pending-retry dispatch for main-agent turns."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import asyncio
8
+ from collections.abc import Awaitable, Callable
9
+ from dataclasses import dataclass
10
+ from datetime import datetime
11
+ from typing import TYPE_CHECKING, Protocol
12
+
13
+ from chrys.foundation.events.types import Error, UserRetry, Warning
14
+ from chrys.foundation.i18n import msg
15
+ from chrys.foundation.models.history_markers import HistoryMarkerKind
16
+ from chrys.foundation.models.turns import current_turn_start, is_continuation_message
17
+ from chrys.orchestration.engine.execution import (
18
+ CurrentRunInjectionWindow,
19
+ CurrentRunScope,
20
+ PreAdmissionPreparationEntry,
21
+ PreAdmissionPreparationTracker,
22
+ PromptAdmissionScope,
23
+ )
24
+ from chrys.orchestration.engine.run.active_injection import ActiveTurnInjector
25
+ from chrys.orchestration.engine.run.input_refs import format_skill_reference_reminder, parse_skill_reference
26
+ from chrys.orchestration.engine.run.prompt_content import PromptContentPreparer
27
+ from chrys.orchestration.engine.run.runtime_skills import (
28
+ CommittedSkillRefresh,
29
+ RuntimeSkillRefresher,
30
+ StagedRuntimeSkillRefresh,
31
+ )
32
+ from chrys.orchestration.engine.run.turn_hooks import PromptSubmitGate
33
+ from chrys.orchestration.engine.run.turn_state import ActiveInjectionTarget
34
+ from chrys.orchestration.engine.run.working_dir import publish_working_dir_missing, refuse_while_working_dir_missing
35
+ from chrys.orchestration.engine.state.machine import EngineState, Trigger
36
+ from chrys.service.hooks.schema import HookDecision
37
+ from chrys.service.trajectory.preparation import (
38
+ PreparationOutcome,
39
+ PreparationScope,
40
+ PreparationTrace,
41
+ input_admission_wait,
42
+ )
43
+
44
+ if TYPE_CHECKING:
45
+ from chrys.foundation.events.bus import EventBus
46
+ from chrys.foundation.events.types import RuntimeSkillDetails
47
+ from chrys.orchestration.engine.run.bindings import TurnBindings
48
+ from chrys.orchestration.engine.run.turn_state import TurnRuntimeState
49
+ from chrys.orchestration.engine.state.active_session import ActiveSession
50
+ from chrys.orchestration.engine.state.current_agent import CurrentAgent
51
+ from chrys.orchestration.engine.state.lifecycle_permits import LifecyclePermits
52
+ from chrys.orchestration.engine.state.machine import EngineStateMachine
53
+ from chrys.orchestration.engine.trajectory import TrajectoryRecorder
54
+ from chrys.orchestration.invoker.kernel import KernelConversation
55
+ from chrys.service.agent_middleware.system_reminder import (
56
+ CurrentRunReminderScope,
57
+ CurrentRunReminderTarget,
58
+ SystemReminderMiddleware,
59
+ )
60
+ from chrys.service.session.history import SessionHistoryManager
61
+
62
+
63
+ _RETRY_MISSING_USER_ANCHOR = msg(
64
+ "retry.missing_user_anchor",
65
+ fallback="Cannot retry without a real user message in history.",
66
+ )
67
+ _RETRY_SUB_AGENT_PAUSED = msg(
68
+ "retry.sub_agent_paused",
69
+ fallback="Resolve paused sub-agent(s) first (Retry/Abort on the card) before retrying the main run.",
70
+ )
71
+
72
+
73
+ @dataclass(frozen=True)
74
+ class _CurrentRunSideEffectTarget:
75
+ """Captured current-run owner for non-injection retry-note side effects."""
76
+
77
+ session_id: str | None
78
+ session_generation: int
79
+ build_generation: int
80
+ current_run_scope: CurrentRunScope
81
+ bindings: TurnBindings
82
+ conversation: KernelConversation
83
+ reminder_middleware: SystemReminderMiddleware
84
+ reminder_target: CurrentRunReminderTarget
85
+
86
+
87
+ @dataclass(frozen=True)
88
+ class _RetryNoteOwner:
89
+ """Session/build/current-run owner captured before retry-note hook awaits."""
90
+
91
+ session_id: str | None
92
+ session_generation: int
93
+ build_generation: int
94
+ current_run_scope: CurrentRunScope | None
95
+ bindings: TurnBindings
96
+ conversation: KernelConversation
97
+ reminder_middleware: SystemReminderMiddleware | None
98
+
99
+
100
+ @dataclass(frozen=True)
101
+ class _PreparedRetryNoteSideEffects:
102
+ """Retry-note reminders and staged skill refresh ready for a concrete run scope."""
103
+
104
+ reminders: list[str]
105
+ staged: StagedRuntimeSkillRefresh | None
106
+
107
+
108
+ class RetryPassRunner(Protocol):
109
+ """Execute an admitted retry and save its terminal state."""
110
+
111
+ async def __call__(
112
+ self,
113
+ additional_text: str = "",
114
+ created_at: datetime | str | None = None,
115
+ *,
116
+ run_scope: CurrentRunScope | None = None,
117
+ injection_window: CurrentRunInjectionWindow | None = None,
118
+ admission_preparation: PreparationTrace | None = None,
119
+ ) -> None: ...
120
+
121
+
122
+ class RetryCoordinator:
123
+ """Own retry admission, pending retry state, and retry task creation."""
124
+
125
+ def __init__(
126
+ self,
127
+ *,
128
+ turn_state: TurnRuntimeState,
129
+ current: CurrentAgent,
130
+ permits: LifecyclePermits,
131
+ session: ActiveSession,
132
+ fsm: EngineStateMachine,
133
+ history: SessionHistoryManager,
134
+ bus: EventBus,
135
+ trajectory_recorder: TrajectoryRecorder,
136
+ gate: PromptSubmitGate,
137
+ injector: ActiveTurnInjector,
138
+ content: PromptContentPreparer,
139
+ skills: RuntimeSkillRefresher,
140
+ retry_and_save: RetryPassRunner,
141
+ ) -> None:
142
+ self._turn_state = turn_state
143
+ self._current = current
144
+ self._permits = permits
145
+ self._session = session
146
+ self._fsm = fsm
147
+ self._history = history
148
+ self._bus = bus
149
+ self._trajectory_recorder = trajectory_recorder
150
+ self._gate = gate
151
+ self._injector = injector
152
+ self._content = content
153
+ self._skills = skills
154
+ self._retry_and_save = retry_and_save
155
+ self._preparation_handed_off = False
156
+
157
+ def _open_pre_turn_preparation(self) -> PreparationTrace | None:
158
+ """Open a session-root preparation scope before retry admission awaits."""
159
+ context = self._trajectory_recorder.context()
160
+ if context is not None:
161
+ context = context.with_turn(None).with_run(None)
162
+ return PreparationTrace.open(
163
+ scope=PreparationScope.PRE_TURN,
164
+ phase="input_admission",
165
+ context=context,
166
+ )
167
+
168
+ async def _start_pre_admission_preparation(self, tracker: PreAdmissionPreparationTracker) -> None:
169
+ """Start and register a retry preparation against the current session."""
170
+ preparation = self._open_pre_turn_preparation()
171
+ if preparation is None:
172
+ tracker.current = None
173
+ return
174
+ entry = PreAdmissionPreparationEntry(preparation=preparation)
175
+ tracker.current = entry
176
+ await preparation.started()
177
+ self._turn_state.lease.register_pre_admission_preparation(entry)
178
+
179
+ async def _wait_for_pre_admission_gate(
180
+ self,
181
+ wait_for_gate: Callable[[], Awaitable[object]],
182
+ tracker: PreAdmissionPreparationTracker,
183
+ ) -> None:
184
+ """Wait at one gate and rebind a preparation swept by a session boundary."""
185
+ entry = tracker.current
186
+ preparation = tracker.preparation
187
+ await input_admission_wait(wait_for_gate, preparation, entry)
188
+ if preparation is None or not preparation.finished_state:
189
+ return
190
+ self._turn_state.lease.deregister_pre_admission_preparation(entry)
191
+ await self._start_pre_admission_preparation(tracker)
192
+
193
+ @staticmethod
194
+ async def _finish_preparation(preparation: PreparationTrace | None, outcome: str) -> None:
195
+ if preparation is not None:
196
+ await preparation.finished(outcome=outcome)
197
+
198
+ async def handle_user_retry(self, event: UserRetry) -> None:
199
+ """Handle retry requests and route them to immediate or pending execution."""
200
+ if await self._turn_state.lease.refuse_while_workflow_active(self._bus, self._session.session_id):
201
+ return
202
+ preparation_tracker = PreAdmissionPreparationTracker()
203
+ try:
204
+ await self._start_pre_admission_preparation(preparation_tracker)
205
+ await self._handle_user_retry(event, preparation_tracker=preparation_tracker)
206
+ except asyncio.CancelledError:
207
+ preparation = preparation_tracker.preparation
208
+ if preparation is not None:
209
+ preparation.finished_soon(outcome=PreparationOutcome.CANCELLED)
210
+ raise
211
+ except BaseException:
212
+ preparation = preparation_tracker.preparation
213
+ if preparation is not None:
214
+ preparation.finished_soon(outcome=PreparationOutcome.PREPARATION_FAILED)
215
+ raise
216
+ finally:
217
+ self._turn_state.lease.deregister_pre_admission_preparation(preparation_tracker.current)
218
+ preparation = preparation_tracker.preparation
219
+ pending_owns_preparation = self._turn_state.lease.pending_retry.preparation_trace is preparation
220
+ if (
221
+ preparation is not None
222
+ and not self._preparation_handed_off
223
+ and not pending_owns_preparation
224
+ and not preparation.finished_state
225
+ ):
226
+ await preparation.finished(outcome=PreparationOutcome.PREPARATION_FAILED)
227
+
228
+ async def _handle_user_retry(
229
+ self,
230
+ event: UserRetry,
231
+ *,
232
+ preparation_tracker: PreAdmissionPreparationTracker,
233
+ ) -> None:
234
+ """Execute one retry admission under its pre-turn preparation scope."""
235
+ admission: PromptAdmissionScope | None = None
236
+ admission_released = False
237
+ while True:
238
+ await self._wait_for_pre_admission_gate(self._permits.wait_for_agent_load_idle, preparation_tracker)
239
+ preparation = preparation_tracker.preparation
240
+ if self._current.loaded is None:
241
+ if self._turn_state.lease.prompt_admission_closed:
242
+ await self._wait_for_pre_admission_gate(
243
+ self._turn_state.lease.wait_for_prompt_admission_open,
244
+ preparation_tracker,
245
+ )
246
+ continue
247
+ await self._finish_preparation(preparation, PreparationOutcome.NOT_READY)
248
+ return
249
+ if self._turn_state.lease.prompt_admission_closed:
250
+ await self._wait_for_pre_admission_gate(
251
+ self._turn_state.lease.wait_for_prompt_admission_open,
252
+ preparation_tracker,
253
+ )
254
+ continue
255
+ if self._turn_state.lease.has_active_admission_kind("fresh"):
256
+ await self._wait_for_pre_admission_gate(
257
+ self._turn_state.lease.wait_for_active_admissions_idle,
258
+ preparation_tracker,
259
+ )
260
+ continue
261
+ if await refuse_while_working_dir_missing(self._bus, self._session):
262
+ await self._finish_preparation(preparation, PreparationOutcome.REJECTED)
263
+ return
264
+ # A workflow run may have taken the lease while this retry was preparing.
265
+ if await self._turn_state.lease.refuse_while_workflow_active(self._bus, self._session.session_id):
266
+ await self._finish_preparation(preparation, PreparationOutcome.REJECTED)
267
+ return
268
+ if not self._has_real_user_anchor():
269
+ await self._bus.publish(
270
+ Error(
271
+ code="retry_missing_user_anchor",
272
+ message="Cannot retry without a real user message in history.",
273
+ display_message=_RETRY_MISSING_USER_ANCHOR.bind(),
274
+ recoverable=True,
275
+ session_id=self._session.session_id,
276
+ )
277
+ )
278
+ await self._finish_preparation(preparation, PreparationOutcome.REJECTED)
279
+ return
280
+ admission = self._turn_state.lease.reserve_prompt_admission(
281
+ kind="retry",
282
+ session_generation=self._permits.session_generation,
283
+ build_generation=self._permits.build_generation,
284
+ preparation_trace=preparation,
285
+ )
286
+ if admission is None:
287
+ await self._wait_for_pre_admission_gate(
288
+ self._turn_state.lease.wait_for_prompt_admission_open,
289
+ preparation_tracker,
290
+ )
291
+ continue
292
+ self._turn_state.lease.deregister_pre_admission_preparation(preparation_tracker.current)
293
+ break
294
+
295
+ try:
296
+ if self._fsm.is_awaiting_sub_agents():
297
+ await self._bus.publish(
298
+ Warning(
299
+ code="sub_agent_paused",
300
+ message=(
301
+ "Resolve paused sub-agent(s) first (Retry/Abort on the card) before retrying the main run."
302
+ ),
303
+ display_message=_RETRY_SUB_AGENT_PAUSED.bind(),
304
+ session_id=self._session.session_id,
305
+ )
306
+ )
307
+ await self._finish_preparation(preparation, PreparationOutcome.CONFLICT)
308
+ return
309
+ decision: HookDecision | None = None
310
+ retry_note_owner = self._capture_retry_note_owner() if event.text else None
311
+ active_retry_target = (
312
+ self._capture_retry_note_active_target()
313
+ if event.text and self._current.loaded is not None and self._current.loaded.bindings.state.running
314
+ else None
315
+ )
316
+ pending_retry_installed = False
317
+
318
+ def _install_pending_retry_before_commit() -> None:
319
+ nonlocal admission_released, pending_retry_installed
320
+ if active_retry_target is None:
321
+ return
322
+ if (
323
+ self._turn_state.lease.run_task is not active_retry_target.run_task
324
+ or active_retry_target.run_task.done()
325
+ ):
326
+ return
327
+ if not self._pending_retry_request_still_accepted():
328
+ return
329
+ if not self._admission_owner_is_current(admission):
330
+ return
331
+ self._turn_state.lease.upsert_pending_retry_from_admission(admission, event.text, event.timestamp)
332
+ self._preparation_handed_off = True
333
+ self._turn_state.lease.release_prompt_admission(admission)
334
+ admission_released = True
335
+ transition = self._fsm.try_transition(Trigger.RETRY_REQUESTED)
336
+ pending_retry_installed = transition is not None or self._fsm.state == EngineState.PENDING_RETRY
337
+
338
+ if event.text:
339
+ decision = await self._gate.evaluate(
340
+ event.text,
341
+ injected=True,
342
+ target_operation_id=preparation.committed_operation_id if preparation is not None else None,
343
+ trajectory_context=preparation.context if preparation is not None else None,
344
+ )
345
+ if not self._admission_owner_is_current(admission) or self._retry_note_owner_stale_after_hook(
346
+ retry_note_owner, active_retry_target
347
+ ):
348
+ await self._finish_preparation(preparation, PreparationOutcome.OWNER_CHANGED)
349
+ self._clear_pending_retry_for_admission_or_unowned(admission)
350
+ return
351
+ retry_note_session_id = retry_note_owner.session_id if retry_note_owner is not None else None
352
+ if await self._gate.handle_decision(
353
+ decision,
354
+ injected=True,
355
+ session_id=retry_note_session_id,
356
+ ):
357
+ await self._finish_preparation(preparation, PreparationOutcome.REJECTED)
358
+ self._clear_pending_retry_for_admission_or_unowned(admission)
359
+ return
360
+ if await self._reject_retry_images(event.text, session_id=retry_note_session_id):
361
+ await self._finish_preparation(preparation, PreparationOutcome.IMAGE_REJECTED)
362
+ self._clear_pending_retry_for_admission_or_unowned(admission)
363
+ return
364
+ if not self._admission_owner_is_current(admission):
365
+ await self._finish_preparation(preparation, PreparationOutcome.OWNER_CHANGED)
366
+ return
367
+ if await self._reject_text_only_active_history():
368
+ await self._finish_preparation(preparation, PreparationOutcome.IMAGE_REJECTED)
369
+ self._clear_pending_retry_for_admission_or_unowned(admission)
370
+ return
371
+ deferred_retry_note: _PreparedRetryNoteSideEffects | None = None
372
+ if event.text:
373
+ accepted, deferred_retry_note = await self._commit_retry_note_side_effects(
374
+ event.text,
375
+ decision,
376
+ retry_note_owner,
377
+ active_retry_target,
378
+ before_commit=_install_pending_retry_before_commit,
379
+ )
380
+ if not accepted:
381
+ await self._finish_preparation(preparation, PreparationOutcome.PREPARATION_FAILED)
382
+ self._clear_pending_retry_for_admission_or_unowned(admission)
383
+ return
384
+ if pending_retry_installed:
385
+ return
386
+ if (
387
+ self._current.loaded is not None
388
+ and not self._current.loaded.bindings.state.running
389
+ and self._turn_state.lease.run_task is None
390
+ and not self._immediate_retry_start_may_be_valid()
391
+ ):
392
+ await self._finish_preparation(preparation, PreparationOutcome.CONFLICT)
393
+ return
394
+ if self._current.loaded is not None and self._current.loaded.bindings.state.running:
395
+ if self._admission_owner_is_current(admission) and self._pending_retry_request_still_accepted():
396
+ self._turn_state.lease.upsert_pending_retry_from_admission(admission, event.text, event.timestamp)
397
+ self._preparation_handed_off = True
398
+ self._turn_state.lease.release_prompt_admission(admission)
399
+ admission_released = True
400
+ self._fsm.try_transition(Trigger.RETRY_REQUESTED)
401
+ else:
402
+ outcome = (
403
+ PreparationOutcome.CONFLICT
404
+ if self._admission_owner_is_current(admission)
405
+ else PreparationOutcome.OWNER_CHANGED
406
+ )
407
+ await self._finish_preparation(preparation, outcome)
408
+ self._clear_pending_retry_for_admission_or_unowned(admission)
409
+ return
410
+ wait_entry = PreAdmissionPreparationEntry(preparation=preparation) if preparation is not None else None
411
+ if wait_entry is not None:
412
+ self._turn_state.lease.register_pre_admission_preparation(wait_entry)
413
+ try:
414
+ await input_admission_wait(self._wait_for_existing_run_task, preparation, wait_entry)
415
+ finally:
416
+ self._turn_state.lease.deregister_pre_admission_preparation(wait_entry)
417
+ if not self._admission_owner_is_current(admission):
418
+ await self._finish_preparation(preparation, PreparationOutcome.OWNER_CHANGED)
419
+ return
420
+ if self._turn_state.lease.run_task is not None and not self._turn_state.lease.run_task.done():
421
+ await self._finish_preparation(preparation, PreparationOutcome.CONFLICT)
422
+ return
423
+ # The run this retry waited for can end because its directory was deleted.
424
+ if await refuse_while_working_dir_missing(self._bus, self._session):
425
+ await self._finish_preparation(preparation, PreparationOutcome.REJECTED)
426
+ return
427
+ if not self._claim_immediate_retry_start():
428
+ await self._finish_preparation(preparation, PreparationOutcome.CONFLICT)
429
+ return
430
+ if self._current.loaded is None:
431
+ self._turn_state.lease.release_prompt_admission(admission)
432
+ admission_released = True
433
+ self._history.remove_trailing_markers()
434
+ self._turn_state.lease.run_task = asyncio.create_task(
435
+ self._retry_and_save(
436
+ event.text,
437
+ created_at=event.timestamp,
438
+ admission_preparation=preparation,
439
+ )
440
+ )
441
+ self._preparation_handed_off = True
442
+ return
443
+
444
+ self._history.remove_trailing_markers()
445
+ promotion = self._turn_state.lease.promote_retry_admission(
446
+ admission,
447
+ reminder_scope=self._retry_reminder_scope_for_admission(admission),
448
+ make_task=lambda scope, window: asyncio.create_task(
449
+ self._retry_and_save(
450
+ event.text,
451
+ created_at=event.timestamp,
452
+ run_scope=scope,
453
+ injection_window=window,
454
+ admission_preparation=preparation,
455
+ )
456
+ ),
457
+ text=event.text,
458
+ created_at=event.timestamp,
459
+ )
460
+ if promotion.outcome == "task":
461
+ admission_released = True
462
+ self._preparation_handed_off = True
463
+ if deferred_retry_note is not None:
464
+ scope = self._turn_state.lease.current_run_scope
465
+ if scope is None or scope.owner_admission_id != admission.admission_id:
466
+ self._discard_promoted_retry_task(promotion.task, scope)
467
+ await self._finish_preparation(preparation, PreparationOutcome.OWNER_CHANGED)
468
+ self._clear_pending_retry_for_admission_or_unowned(admission)
469
+ return
470
+ if not await self._commit_deferred_retry_note_side_effects(deferred_retry_note, scope):
471
+ self._discard_promoted_retry_task(promotion.task, scope)
472
+ await self._finish_preparation(preparation, PreparationOutcome.PREPARATION_FAILED)
473
+ self._clear_pending_retry_for_admission_or_unowned(admission)
474
+ else:
475
+ await self._finish_preparation(
476
+ preparation,
477
+ PreparationOutcome.OWNER_CHANGED if promotion.outcome == "stale" else PreparationOutcome.CONFLICT,
478
+ )
479
+ finally:
480
+ if admission is not None and not admission_released:
481
+ self._turn_state.lease.release_prompt_admission(admission)
482
+
483
+ def start_pending_retry_if_due(self) -> str | None:
484
+ """Start a queued retry when post-run state allows retry dispatch.
485
+
486
+ Return the working directory only when a due retry was dropped because
487
+ that directory is gone, else None. The finished pass left the FSM
488
+ RUNNING for that retry, so the caller settles it to the pass's own
489
+ terminal state and then reports the drop
490
+ (:meth:`report_retry_dropped_for_missing_cwd`).
491
+ """
492
+ if self._session.shutting_down:
493
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
494
+ return None
495
+ if self._fsm.state != EngineState.RUNNING:
496
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
497
+ return None
498
+ if self._turn_state.lease.pending_retry.dispatch_disabled:
499
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
500
+ return None
501
+ pending = self._turn_state.lease.pending_retry
502
+ scope = self._turn_state.lease.current_run_scope
503
+ if pending.owner_admission_id is None:
504
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
505
+ return None
506
+ if pending.session_generation != self._permits.session_generation:
507
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
508
+ return None
509
+ if pending.run_generation == 0:
510
+ if scope is not None:
511
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
512
+ return None
513
+ elif scope is None or pending.run_generation != scope.run_generation:
514
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
515
+ return None
516
+ if self._turn_state.lease.pending_retry_dispatch_disabled_for_session_generation == pending.session_generation:
517
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
518
+ return None
519
+ workspace = self._session.workspace
520
+ if workspace is not None and (missing := workspace.missing_primary()) is not None:
521
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
522
+ return missing
523
+ self._history.remove_trailing_markers()
524
+ text = pending.text
525
+ created_at = pending.created_at
526
+ dispatched = self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.RETRY_TURN)
527
+ self._turn_state.lease.run_task = self._create_retry_run_task(
528
+ text,
529
+ created_at=created_at,
530
+ admission_preparation=dispatched.preparation_trace,
531
+ )
532
+ return None
533
+
534
+ async def report_retry_dropped_for_missing_cwd(self, path: str) -> None:
535
+ """Tell frontends a queued retry will not run because *path* is gone.
536
+
537
+ A frontend shows an accepted retry as running until a run ends it; no
538
+ run will, so this error does.
539
+ """
540
+ await publish_working_dir_missing(self._bus, self._session.session_id, path)
541
+
542
+ async def _wait_for_existing_run_task(self) -> None:
543
+ """Wait for current run-task cleanup, if any."""
544
+ task = self._turn_state.lease.run_task
545
+ if task is not None and not task.done():
546
+ await task
547
+
548
+ def _reuse_or_create_retry_scope(self) -> CurrentRunScope | None:
549
+ """Return a retry scope, preserving the current logical scope when valid."""
550
+ scope = self._turn_state.lease.current_run_scope
551
+ if (
552
+ scope is not None
553
+ and scope.session_generation == self._permits.session_generation
554
+ and scope.build_generation == self._permits.build_generation
555
+ ):
556
+ return scope
557
+ return None
558
+
559
+ def _reuse_or_create_retry_scope_and_window(self) -> tuple[CurrentRunScope, CurrentRunInjectionWindow] | None:
560
+ """Open a retry injection window, preserving the current logical scope when valid."""
561
+ scope = self._reuse_or_create_retry_scope()
562
+ if scope is not None:
563
+ return scope, self._turn_state.lease.open_injection_admission(scope)
564
+ return None
565
+
566
+ def _create_retry_run_task(
567
+ self,
568
+ text: str,
569
+ *,
570
+ created_at: datetime | str | None,
571
+ admission_preparation: PreparationTrace | None = None,
572
+ ) -> asyncio.Task[None]:
573
+ """Create a retry task, preserving the validated current retry scope."""
574
+ scope_window = self._reuse_or_create_retry_scope_and_window()
575
+ if scope_window is None:
576
+ return asyncio.create_task(
577
+ self._retry_and_save(
578
+ text,
579
+ created_at=created_at,
580
+ admission_preparation=admission_preparation,
581
+ )
582
+ )
583
+ scope, window = scope_window
584
+ return asyncio.create_task(
585
+ self._retry_and_save(
586
+ text,
587
+ created_at=created_at,
588
+ run_scope=scope,
589
+ injection_window=window,
590
+ admission_preparation=admission_preparation,
591
+ )
592
+ )
593
+
594
+ def _discard_promoted_retry_task(
595
+ self,
596
+ task: asyncio.Task[None] | None,
597
+ scope: CurrentRunScope | None,
598
+ ) -> None:
599
+ """Cancel a just-promoted retry task when its deferred admission side effects fail."""
600
+ if task is not None and not task.done():
601
+ task.cancel()
602
+ if self._turn_state.lease.run_task is task:
603
+ self._turn_state.lease.run_task = None
604
+ if scope is not None:
605
+ self._turn_state.lease.clear_current_run_scope(scope)
606
+ if self._current.loaded is not None:
607
+ self._current.loaded.reminder_middleware.expire_current_run_scope(scope.reminder_scope)
608
+ self._fsm.try_transition(Trigger.RUN_FAILED)
609
+
610
+ def _admission_owner_is_current(self, admission: PromptAdmissionScope) -> bool:
611
+ """Return whether *admission* still belongs to the live session/build owner."""
612
+ return (
613
+ self._permits.session_generation == admission.session_generation
614
+ and self._permits.build_generation == admission.build_generation
615
+ )
616
+
617
+ def _has_real_user_anchor(self) -> bool:
618
+ """Return whether the marker-ignoring current logical turn has user input."""
619
+ current_input = self._turn_state.current_input
620
+ if current_input.kind != "continuation" and (current_input.text or current_input.contents):
621
+ # Fresh input may not have landed in provider history yet, but it
622
+ # is the same real anchor crash recovery would synthesize.
623
+ return True
624
+ messages = self._history.messages
625
+ logical_end = len(messages)
626
+ while logical_end:
627
+ kind = messages[logical_end - 1].additional_properties.get(HistoryMarkerKind.KEY)
628
+ if kind not in HistoryMarkerKind.SESSION_COUNT_EXCLUDED:
629
+ break
630
+ logical_end -= 1
631
+ logical_messages = messages[:logical_end]
632
+ start = current_turn_start(logical_messages)
633
+ return any(
634
+ message.role == "user" and not is_continuation_message(message) for message in logical_messages[start:]
635
+ )
636
+
637
+ def _immediate_retry_start_may_be_valid(self) -> bool:
638
+ """Return whether current state may be valid for an immediate retry after cleanup."""
639
+ if self._session.shutting_down:
640
+ return False
641
+ if self._fsm.state in (EngineState.INTERRUPTED, EngineState.FAILED):
642
+ return True
643
+ return (
644
+ self._fsm.state is EngineState.RUNNING
645
+ and self._turn_state.lease.run_task is not None
646
+ and self._turn_state.lease.run_task.done()
647
+ and self._current.loaded is not None
648
+ and not self._current.loaded.bindings.state.running
649
+ )
650
+
651
+ def _claim_immediate_retry_start(self) -> bool:
652
+ """Validate and transition the FSM for an immediate retry before task install."""
653
+ if self._session.shutting_down:
654
+ return False
655
+ if self._fsm.state in (EngineState.INTERRUPTED, EngineState.FAILED):
656
+ self._fsm.try_transition(Trigger.RETRY_STARTED)
657
+ return self._fsm.state is EngineState.RUNNING
658
+ return (
659
+ self._fsm.state is EngineState.RUNNING
660
+ and self._turn_state.lease.run_task is not None
661
+ and self._turn_state.lease.run_task.done()
662
+ and self._current.loaded is not None
663
+ and not self._current.loaded.bindings.state.running
664
+ )
665
+
666
+ def _retry_request_still_accepted(self) -> bool:
667
+ """Return whether retry-note side effects may still be committed."""
668
+ return not self._session.shutting_down and self._fsm.state in (
669
+ EngineState.RUNNING,
670
+ EngineState.PENDING_RETRY,
671
+ EngineState.INTERRUPTED,
672
+ EngineState.FAILED,
673
+ )
674
+
675
+ def _pending_retry_request_still_accepted(self) -> bool:
676
+ """Return whether a retry request may be queued for the active executor."""
677
+ return not self._session.shutting_down and self._fsm.state is EngineState.RUNNING
678
+
679
+ def _clear_pending_retry_for_admission_or_unowned(self, admission: PromptAdmissionScope) -> None:
680
+ """Clear retry state only when it is unowned or belongs to *admission*."""
681
+ pending = self._turn_state.lease.pending_retry
682
+ if pending.owner_admission_id is None or pending.updated_by_admission_id == admission.admission_id:
683
+ self._turn_state.lease.clear_pending_retry(outcome=PreparationOutcome.DROPPED)
684
+
685
+ def _retry_reminder_scope_for_admission(self, admission: PromptAdmissionScope) -> CurrentRunReminderScope:
686
+ """Return the existing logical retry reminder scope, or allocate a new one."""
687
+ current_scope = self._turn_state.lease.current_run_scope
688
+ if (
689
+ current_scope is not None
690
+ and current_scope.session_generation == admission.session_generation
691
+ and current_scope.build_generation == admission.build_generation
692
+ ):
693
+ return current_scope.reminder_scope
694
+ reminder_middleware = self._current.loaded.reminder_middleware if self._current.loaded is not None else None
695
+ if reminder_middleware is None:
696
+ raise RuntimeError("Cannot promote retry without reminder middleware")
697
+ return reminder_middleware.create_current_run_scope()
698
+
699
+ def _capture_retry_note_active_target(self) -> ActiveInjectionTarget | None:
700
+ """Capture the active current-run owner used by retry-note side effects."""
701
+ return self._injector.capture_target(route="fsm_active")
702
+
703
+ def _retry_note_active_target_owner_invalid(self, target: ActiveInjectionTarget) -> bool:
704
+ """Return whether a captured retry-note owner changed beyond executor completion."""
705
+ return self._injector.target_owner_invalid(target)
706
+
707
+ def _capture_retry_note_owner(self) -> _RetryNoteOwner | None:
708
+ """Capture the retry-note owner before awaited prompt-submit hooks run."""
709
+ executor = self._current.loaded.bindings if self._current.loaded is not None else None
710
+ if executor is None:
711
+ return None
712
+ return _RetryNoteOwner(
713
+ session_id=self._session.session_id,
714
+ session_generation=self._permits.session_generation,
715
+ build_generation=self._permits.build_generation,
716
+ current_run_scope=self._turn_state.lease.current_run_scope,
717
+ bindings=executor,
718
+ conversation=executor.backend,
719
+ reminder_middleware=self._current.loaded.reminder_middleware if self._current.loaded is not None else None,
720
+ )
721
+
722
+ def _retry_note_owner_invalid(self, owner: _RetryNoteOwner) -> bool:
723
+ """Return whether the pre-hook retry-note owner changed."""
724
+ return (
725
+ self._session.session_id != owner.session_id
726
+ or self._permits.session_generation != owner.session_generation
727
+ or self._permits.build_generation != owner.build_generation
728
+ or (self._current.loaded is None or self._current.loaded.bindings.backend is not owner.conversation)
729
+ or self._current.loaded.reminder_middleware is not owner.reminder_middleware
730
+ )
731
+
732
+ def _retry_note_owner_scope_conflicted(self, owner: _RetryNoteOwner) -> bool:
733
+ """Return whether a different live current-run scope replaced the pre-hook owner."""
734
+ current_scope = self._turn_state.lease.current_run_scope
735
+ return current_scope is not None and current_scope != owner.current_run_scope
736
+
737
+ def _capture_current_run_side_effect_target(self, scope: CurrentRunScope) -> _CurrentRunSideEffectTarget | None:
738
+ """Capture a current-run reminder target for scoped retry-note side effects."""
739
+ executor = self._current.loaded.bindings if self._current.loaded is not None else None
740
+ reminder_middleware = self._current.loaded.reminder_middleware if self._current.loaded is not None else None
741
+ if executor is None or reminder_middleware is None:
742
+ return None
743
+ if (
744
+ scope.session_generation != self._permits.session_generation
745
+ or scope.build_generation != self._permits.build_generation
746
+ ):
747
+ return None
748
+ if self._turn_state.lease.current_run_scope != scope:
749
+ return None
750
+ reminder_target = reminder_middleware.capture_current_run_target(scope.reminder_scope)
751
+ if reminder_target is None:
752
+ return None
753
+ return _CurrentRunSideEffectTarget(
754
+ session_id=self._session.session_id,
755
+ session_generation=self._permits.session_generation,
756
+ build_generation=self._permits.build_generation,
757
+ current_run_scope=scope,
758
+ bindings=executor,
759
+ conversation=executor.backend,
760
+ reminder_middleware=reminder_middleware,
761
+ reminder_target=reminder_target,
762
+ )
763
+
764
+ def _current_run_side_effect_target_is_current(self, target: _CurrentRunSideEffectTarget) -> bool:
765
+ """Return whether a scoped retry-note side-effect owner remains current."""
766
+ return (
767
+ self._session.session_id == target.session_id
768
+ and self._permits.session_generation == target.session_generation
769
+ and self._permits.build_generation == target.build_generation
770
+ and self._turn_state.lease.current_run_scope == target.current_run_scope
771
+ and self._current.loaded is not None
772
+ and self._current.loaded.bindings.backend is target.conversation
773
+ and self._current.loaded.reminder_middleware is target.reminder_middleware
774
+ )
775
+
776
+ def _retry_note_owner_stale_after_hook(
777
+ self,
778
+ owner: _RetryNoteOwner | None,
779
+ active_retry_target: ActiveInjectionTarget | None,
780
+ ) -> bool:
781
+ """Return whether a retry note owner became stale while hooks awaited."""
782
+ if owner is None or self._retry_note_owner_invalid(owner) or self._retry_note_owner_scope_conflicted(owner):
783
+ return True
784
+ return active_retry_target is not None and self._retry_note_active_target_owner_invalid(active_retry_target)
785
+
786
+ async def _commit_retry_note_side_effects(
787
+ self,
788
+ text: str,
789
+ decision: HookDecision | None,
790
+ owner: _RetryNoteOwner | None,
791
+ active_retry_target: ActiveInjectionTarget | None,
792
+ *,
793
+ before_commit: Callable[[], None] | None = None,
794
+ ) -> tuple[bool, _PreparedRetryNoteSideEffects | None]:
795
+ """Commit retry-note side effects, or defer them until retry promotion creates a scope."""
796
+ if not text:
797
+ return True, None
798
+ if not self._retry_request_still_accepted():
799
+ return False, None
800
+ if owner is None or self._retry_note_owner_invalid(owner) or self._retry_note_owner_scope_conflicted(owner):
801
+ return False, None
802
+
803
+ staged = await self._stage_runtime_skills()
804
+ if (
805
+ not self._retry_request_still_accepted()
806
+ or self._retry_note_owner_invalid(owner)
807
+ or self._retry_note_owner_scope_conflicted(owner)
808
+ ):
809
+ return False, None
810
+
811
+ side_effects = self._prepare_retry_note_side_effects(text, decision, staged)
812
+
813
+ target: _CurrentRunSideEffectTarget | None = None
814
+ if active_retry_target is not None:
815
+ if self._retry_note_active_target_owner_invalid(active_retry_target):
816
+ return False, None
817
+ current_scope = self._turn_state.lease.current_run_scope
818
+ if current_scope == active_retry_target.current_run_scope:
819
+ target = _CurrentRunSideEffectTarget(
820
+ session_id=active_retry_target.session_id,
821
+ session_generation=active_retry_target.session_generation,
822
+ build_generation=active_retry_target.build_generation,
823
+ current_run_scope=active_retry_target.current_run_scope,
824
+ bindings=active_retry_target.bindings,
825
+ conversation=active_retry_target.conversation,
826
+ reminder_middleware=active_retry_target.reminder_middleware,
827
+ reminder_target=active_retry_target.reminder_target,
828
+ )
829
+ elif current_scope is not None:
830
+ return False, None
831
+
832
+ if target is None:
833
+ scope = self._reuse_or_create_retry_scope()
834
+ if scope is None:
835
+ return True, side_effects
836
+ target = self._capture_current_run_side_effect_target(scope)
837
+ if target is None:
838
+ return False, None
839
+
840
+ if not await self._commit_retry_note_side_effects_to_target(
841
+ side_effects,
842
+ target,
843
+ before_commit=before_commit,
844
+ ):
845
+ return False, None
846
+ return True, None
847
+
848
+ def _prepare_retry_note_side_effects(
849
+ self,
850
+ text: str,
851
+ decision: HookDecision | None,
852
+ staged: StagedRuntimeSkillRefresh | None,
853
+ ) -> _PreparedRetryNoteSideEffects:
854
+ """Build retry-note side effects after hooks and skill refresh have settled."""
855
+ reminders = PromptSubmitGate.reminder_texts(decision)
856
+ skill_reference = self._skill_reference_reminder(
857
+ text,
858
+ skill_details=staged.skill_details if staged is not None else None,
859
+ )
860
+ if skill_reference is not None:
861
+ reminders.append(skill_reference)
862
+ return _PreparedRetryNoteSideEffects(reminders=reminders, staged=staged)
863
+
864
+ async def _commit_retry_note_side_effects_to_target(
865
+ self,
866
+ side_effects: _PreparedRetryNoteSideEffects,
867
+ target: _CurrentRunSideEffectTarget,
868
+ *,
869
+ before_commit: Callable[[], None] | None = None,
870
+ ) -> bool:
871
+ """Commit prepared retry-note side effects to a captured current-run target."""
872
+ if not self._retry_request_still_accepted() or not self._current_run_side_effect_target_is_current(target):
873
+ return False
874
+ if not target.reminder_middleware.is_current_run_target_valid(target.reminder_target):
875
+ return False
876
+
877
+ staged = side_effects.staged
878
+ if staged is not None and not target.reminder_middleware.set_skill_catalog_for_current_run(
879
+ target.reminder_target,
880
+ staged.skill_catalog,
881
+ ):
882
+ return False
883
+ if not target.reminder_middleware.queue_hook_reminders_for_current_run(
884
+ target.reminder_target,
885
+ side_effects.reminders,
886
+ ):
887
+ return False
888
+ if before_commit is not None:
889
+ before_commit()
890
+ if not self._retry_request_still_accepted() or not self._current_run_side_effect_target_is_current(target):
891
+ return False
892
+ if not target.reminder_middleware.is_current_run_target_valid(target.reminder_target):
893
+ return False
894
+
895
+ committed = self._commit_staged_runtime_skills(staged)
896
+ await self._publish_staged_runtime_skill_refresh(
897
+ committed,
898
+ session_id=target.session_id,
899
+ )
900
+ return True
901
+
902
+ async def _commit_deferred_retry_note_side_effects(
903
+ self,
904
+ side_effects: _PreparedRetryNoteSideEffects,
905
+ scope: CurrentRunScope,
906
+ ) -> bool:
907
+ """Commit deferred retry-note side effects after retry admission owns a real scope."""
908
+ target = self._capture_current_run_side_effect_target(scope)
909
+ if target is None:
910
+ return False
911
+ return await self._commit_retry_note_side_effects_to_target(side_effects, target)
912
+
913
+ async def _reject_retry_images(self, text: str, *, session_id: str | None = None) -> bool:
914
+ """Publish a non-fatal rejection for retry notes containing image mentions."""
915
+ return await self._content.reject_retry_images(text, session_id=session_id)
916
+
917
+ async def _reject_text_only_active_history(self) -> bool:
918
+ """Publish a text-only model rejection when active history contains image content."""
919
+ return await self._content.reject_text_only_active_history()
920
+
921
+ async def _stage_runtime_skills(self) -> StagedRuntimeSkillRefresh | None:
922
+ """Discover runtime skills without mutating live provider or host runtime state."""
923
+ return await self._skills.stage_refresh()
924
+
925
+ def _commit_staged_runtime_skills(self, staged: StagedRuntimeSkillRefresh | None) -> CommittedSkillRefresh | None:
926
+ """Commit a staged runtime skill refresh synchronously to the captured owner."""
927
+ return self._skills.commit_staged_refresh(staged)
928
+
929
+ async def _publish_staged_runtime_skill_refresh(
930
+ self,
931
+ committed: CommittedSkillRefresh | None,
932
+ *,
933
+ session_id: str | None,
934
+ ) -> None:
935
+ """Publish warning/runtime update events for a committed staged refresh."""
936
+ await self._skills.publish_committed_refresh(committed, session_id=session_id)
937
+
938
+ def _skill_reference_reminder(
939
+ self,
940
+ text: str,
941
+ *,
942
+ skill_details: list[RuntimeSkillDetails] | None = None,
943
+ ) -> str | None:
944
+ """Return the skill-reference reminder for *text*, if it names a loaded skill."""
945
+ reference = parse_skill_reference(text, skill_details or self._current.manifest.runtime_details.skill_details)
946
+ if reference is None:
947
+ return None
948
+ return format_skill_reference_reminder(reference)