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,894 @@
1
+ # Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
2
+
3
+ """The workflow shell around one agent-node activation.
4
+
5
+ One shell per activation: :meth:`WorkflowAgentShell.open` builds a private
6
+ kernel or ACP conversation for the node's agent and model binding, :meth:`run`
7
+ executes one pass per scheduler attempt, :meth:`abort` converges the in-flight
8
+ pass with a caller cause, and :meth:`close` unbinds and releases everything in
9
+ reverse. The shell is the third caller of the invoker contract after the main
10
+ turn and the sub-agent tool. Inside a pass a kernel node retries a failed
11
+ request as the chat agent does, in place on the wire or as a whole run under
12
+ service-side storage; across passes the scheduler decides from the
13
+ :class:`FailureReport` each attempt yields, and the shell resumes what the
14
+ failed pass left: a kernel pass continues its repaired history, an ACP pass
15
+ starts a new session.
16
+
17
+ Every scheduler attempt publishes under its own origin, so a presentation
18
+ never folds one attempt's late facts into another.
19
+
20
+ Kernel nodes are built like the chat agent — builtin, sub-agent, MCP and skill
21
+ tools plus the profile's auto-loaded memory — and the ``ask_user`` tool is
22
+ dropped whenever the run is headless. No workflow surface shows a per-child
23
+ card, so a failed child ends at once instead of pausing; the shell routes the
24
+ engine's approval mode and the run's abort to the node's own sub-agents.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import asyncio
30
+ import logging
31
+ from collections.abc import Awaitable, Mapping
32
+ from contextvars import ContextVar
33
+ from dataclasses import dataclass, replace
34
+ from typing import TYPE_CHECKING, Any, Final, Literal
35
+
36
+ from chrys.foundation.errors import ErrorKind, classify_error, clean_error_message, is_retryable
37
+ from chrys.foundation.errors.display import display_fields
38
+ from chrys.foundation.events.types import (
39
+ InvocationMessage,
40
+ InvocationResumed,
41
+ InvocationRetryAttempt,
42
+ InvocationStarted,
43
+ )
44
+ from chrys.foundation.hosted_tools import HostedToolStatus
45
+ from chrys.foundation.models.invocations import InvocationOrigin
46
+ from chrys.foundation.trajectory.context import TRAJECTORY_CONTEXT_KWARG, TrajectoryContext, workflow_node_actor
47
+ from chrys.foundation.trajectory.ids import new_analytics_id
48
+ from chrys.foundation.trajectory.metadata import ensure_analytics_item_id
49
+ from chrys.foundation.util.once_close import finish_close
50
+ from chrys.kernel import AgentResponse, Message
51
+ from chrys.orchestration.invoker.acp import AcpConversation, AcpInvocationCounters
52
+ from chrys.orchestration.invoker.acp_protocol import AcpUpdateTranslator
53
+ from chrys.orchestration.invoker.attempts import drop_continuation_token, has_live_continuation_token
54
+ from chrys.orchestration.invoker.child_history import active_input_message
55
+ from chrys.orchestration.invoker.contracts import (
56
+ AbortCause,
57
+ Aborted,
58
+ ContinuationTicket,
59
+ Failed,
60
+ FailureCategory,
61
+ InvocationOutcome,
62
+ Ok,
63
+ OverlappingRun,
64
+ PreparedClosed,
65
+ RunIntent,
66
+ RunRequest,
67
+ StaleContinuation,
68
+ Unbind,
69
+ UnsupportedRequest,
70
+ )
71
+ from chrys.orchestration.invoker.evidence import InvocationEvidence
72
+ from chrys.orchestration.invoker.kernel import KernelConversation
73
+ from chrys.orchestration.invoker.origin import BoundEmitter
74
+ from chrys.orchestration.invoker.resources import Conversation, PassResources, PreparedAgent
75
+ from chrys.orchestration.workflows.agent_archive import CoalescedCheckpoint
76
+ from chrys.orchestration.workflows.agent_node_build import (
77
+ AcpNodeParts,
78
+ AgentNodeCallbacks,
79
+ AgentNodeResources,
80
+ KernelNodeParts,
81
+ build_acp_node,
82
+ build_kernel_node,
83
+ )
84
+ from chrys.service.agent_middleware.events.hosted_tools import FinalSegment
85
+ from chrys.service.agent_middleware.events.intermediate_text import IntermediateTextBuffer
86
+ from chrys.service.agent_middleware.response_validation import hosted_commits_from_error
87
+ from chrys.service.session.history import SessionHistoryManager, stamp_history_item_ids
88
+ from chrys.service.session.sub_agent_logs import SubAgentLogStats
89
+ from chrys.service.workflows.scheduler import ErrorClass, FailureReport
90
+ from chrys.service.workflows.store import WorkflowStorageFailed
91
+
92
+ if TYPE_CHECKING:
93
+ from chrys.foundation.retry import RetryAttemptInfo
94
+ from chrys.orchestration.workflows.agent_archive import AgentNodeArchive
95
+ from chrys.service.approval.policy import ApprovalMode
96
+ from chrys.service.workflows.admission import AgentBinding
97
+
98
+ logger = logging.getLogger(__name__)
99
+
100
+ # The shell whose pass the current task runs under; every task the kernel starts for a pass inherits it.
101
+ _PASS_SHELL: ContextVar[WorkflowAgentShell | None] = ContextVar("chrys.workflow.pass_shell", default=None)
102
+
103
+ ABORT_GRACE: Final = 10.0
104
+ """Seconds a timed-out pass may take to converge after its abort before the run task is cancelled."""
105
+ _TERMINAL_CAUSES: Final = frozenset({AbortCause.USER_CANCEL, AbortCause.RUN_TERMINAL, AbortCause.OWNER_CLOSE})
106
+ # ACP failure categories a new session can overturn; the rest end the same way again.
107
+ _RETRYABLE_ACP_CATEGORIES: Final = frozenset({FailureCategory.TRANSPORT, FailureCategory.REMOTE_ERROR})
108
+
109
+ AttemptKind = Literal["completed", "failed", "cancelled"]
110
+
111
+
112
+ @dataclass(frozen=True, slots=True)
113
+ class AgentAttemptResult:
114
+ """How one pass ended: ``completed`` with the response text, ``failed`` with a report, or ``cancelled``."""
115
+
116
+ kind: AttemptKind
117
+ text: str = ""
118
+ failure: FailureReport | None = None
119
+
120
+
121
+ class WorkflowAgentShell:
122
+ """One agent activation: a private conversation, one pass per attempt, and the caller's abort latch.
123
+
124
+ The shell is both the conversation's operation binding (``request_close`` /
125
+ ``drained``) and the kernel's pass observer; both interfaces are small and
126
+ keep the cancel story in one place.
127
+ """
128
+
129
+ def __init__(
130
+ self,
131
+ *,
132
+ binding: AgentBinding,
133
+ node_id: str,
134
+ invocation_id: str,
135
+ resources: AgentNodeResources,
136
+ archive: AgentNodeArchive,
137
+ ) -> None:
138
+ self._binding = binding
139
+ self._node_id = node_id
140
+ self._invocation_id = invocation_id
141
+ self._resources = resources
142
+ self._archive = archive
143
+ self._archive_attempt = 1
144
+ self._checkpoint: CoalescedCheckpoint | None = None
145
+ self._stats = SubAgentLogStats()
146
+ self._intermediate_buffer = IntermediateTextBuffer()
147
+ self._acp_translators: list[AcpUpdateTranslator] = []
148
+ self._acp_counters = AcpInvocationCounters()
149
+ self._display_name = binding.agent.display_name or binding.agent.name
150
+ self.origin = InvocationOrigin("workflow_node", resources.session_id, invocation_id, None, attempt=1)
151
+ """The origin of the current scheduler attempt; every pass and fact of that attempt carries it."""
152
+ self._emitter = BoundEmitter(resources.bus, self.origin)
153
+ self._prepared = PreparedAgent()
154
+ self._unbind: Unbind | None = None
155
+ self._parts: KernelNodeParts | AcpNodeParts | None = None
156
+ self._is_prepared = False
157
+ self._abort_cause: AbortCause | None = None
158
+ self._run_task: asyncio.Task[InvocationOutcome] | None = None
159
+ self._close_task: asyncio.Task[None] | None = None
160
+ self._ticket: ContinuationTicket | None = None
161
+ self._resume = False
162
+ """Whether the last pass left kernel history for the next attempt to continue."""
163
+ self._evidence = InvocationEvidence(invocation_id)
164
+ self._passes = 0
165
+ self._usage_total = 0
166
+ self._seed_item_id = new_analytics_id()
167
+ self._prompt = ""
168
+ self._active_run_input: list[Any] = []
169
+ self._pass_start_index = 0
170
+
171
+ # ------------------------------------------------------------------ identity
172
+
173
+ @property
174
+ def is_prepared(self) -> bool:
175
+ """Whether this activation opened, even if its backend retired before retry."""
176
+ return self._is_prepared
177
+
178
+ @property
179
+ def _backend(self) -> KernelConversation | AcpConversation | None:
180
+ return self._parts.backend if self._parts is not None else None
181
+
182
+ @property
183
+ def invocation_id(self) -> str:
184
+ return self._invocation_id
185
+
186
+ def abort_cause(self) -> AbortCause | None:
187
+ """The latched caller cause; also the kernel observer's abort-cause port."""
188
+ return self._abort_cause
189
+
190
+ @property
191
+ def evidence(self) -> InvocationEvidence:
192
+ """Every converged pass of this activation, accumulated."""
193
+ return self._evidence
194
+
195
+ # ------------------------------------------------------------------ lifecycle
196
+
197
+ async def open(self, prompt: str, *, attempt: int = 1) -> None:
198
+ """Build the conversation, bind this shell as its operation, and announce the invocation."""
199
+ self._bind_attempt(attempt)
200
+ await self._open_backend()
201
+ self._is_prepared = True
202
+ await self._emitter.publish(
203
+ InvocationStarted(
204
+ origin=self.origin,
205
+ agent_name=self._display_name,
206
+ tool_name=self._node_id,
207
+ session_id=self._session_id,
208
+ opening_prompt=self._user_prompt(prompt),
209
+ )
210
+ )
211
+
212
+ def _bind_attempt(self, attempt: int) -> None:
213
+ """Publish everything from here on as *attempt*; the previous attempt's pass has drained."""
214
+ if attempt != self.origin.attempt:
215
+ self.origin = replace(self.origin, attempt=attempt)
216
+ self._emitter = BoundEmitter(self._resources.bus, self.origin)
217
+
218
+ async def _open_backend(self) -> None:
219
+ conversation = await self._prepared.open(self._open_conversation)
220
+ self._unbind = conversation.bind_operation(self)
221
+
222
+ async def _reopen_backend(self) -> FailureReport | None:
223
+ """Open a backend for a retry after the last one was retired; a failure fails only this attempt."""
224
+ try:
225
+ await self._open_backend()
226
+ except WorkflowStorageFailed:
227
+ raise
228
+ except Exception as exc:
229
+ logger.warning("workflow node %s: agent could not reopen", self._node_id, exc_info=True)
230
+ # A partial open may have left parts over a rolled-back conversation; the next attempt reopens.
231
+ await self._retire_backend()
232
+ return FailureReport(ErrorClass.AGENT_NON_TRANSIENT, f"{type(exc).__name__}: {exc}")
233
+ return None
234
+
235
+ async def _retire_backend(self) -> None:
236
+ """End a backend lifetime without ending the activation or its accounting.
237
+
238
+ A teardown failure is only logged: the attempt's own result stands, and the next attempt opens anew.
239
+ """
240
+ unbind, self._unbind = self._unbind, None
241
+ if unbind is not None:
242
+ unbind()
243
+ try:
244
+ await self._prepared.aclose()
245
+ except Exception:
246
+ logger.warning("workflow node %s: retired agent did not close cleanly", self._node_id, exc_info=True)
247
+ finally:
248
+ self._prepared = PreparedAgent()
249
+ self._parts = None
250
+ self._ticket = None
251
+ self._resume = False
252
+
253
+ async def close(self) -> None:
254
+ """Release the conversation, then drain the session's usage tail (including other publishers).
255
+
256
+ Safe to call more than once. The shared drain keeps session persistence behind usage delivery.
257
+ """
258
+ if self._close_task is None:
259
+ self._close_task = asyncio.create_task(self._close(), name="chrys.workflow.agent.close")
260
+ await finish_close(self._close_task)
261
+
262
+ async def _close(self) -> None:
263
+ _PASS_SHELL.set(self)
264
+ unbind, self._unbind = self._unbind, None
265
+ if unbind is not None:
266
+ unbind()
267
+ await self._flush_progress()
268
+ try:
269
+ await self._prepared.aclose()
270
+ if self._checkpoint is not None:
271
+ await self._checkpoint.close()
272
+ finally:
273
+ await self._resources.usage_publisher.drain()
274
+
275
+ async def _flush_progress(self) -> None:
276
+ if isinstance(self._parts, KernelNodeParts):
277
+ try:
278
+ await self._parts.events.flush_progress()
279
+ except Exception:
280
+ logger.debug("workflow node %s: progress flush failed", self._node_id, exc_info=True)
281
+
282
+ async def run(
283
+ self,
284
+ prompt: str,
285
+ *,
286
+ timeout: float | None,
287
+ trajectory_context: TrajectoryContext | None,
288
+ attempt: int = 1,
289
+ ) -> AgentAttemptResult:
290
+ """Archive this attempt after its pass has drained, including cancellation."""
291
+ self._bind_attempt(attempt)
292
+ self._checkpoint = CoalescedCheckpoint(self._save_transcript)
293
+ self._archive_attempt = attempt
294
+ self._acp_translators.clear()
295
+ result: AgentAttemptResult | None = None
296
+ error = ""
297
+ try:
298
+ if self._backend is None and (failure := await self._reopen_backend()) is not None:
299
+ result = AgentAttemptResult("failed", failure=failure)
300
+ return result
301
+ result = await self._run(prompt, timeout=timeout, trajectory_context=trajectory_context)
302
+ return result
303
+ except asyncio.CancelledError:
304
+ raise
305
+ except Exception as exc:
306
+ error = f"{type(exc).__name__}: {exc}"
307
+ raise
308
+ finally:
309
+ await finish_close(asyncio.create_task(self._finish_attempt(result, error)))
310
+
311
+ async def _finish_attempt(self, result: AgentAttemptResult | None, error: str) -> None:
312
+ # Delivery belongs to the pass boundary, even while the activation is
313
+ # retained for outgoing-condition evaluation and possible retries.
314
+ _PASS_SHELL.set(self)
315
+ await self._flush_progress()
316
+ await self._resources.usage_publisher.drain()
317
+ await self._require_checkpoint().close()
318
+ await self._save_transcript(
319
+ status=result.kind if result is not None else "failed" if error else "cancelled",
320
+ error=result.failure.message if result is not None and result.failure is not None else error,
321
+ )
322
+ if (
323
+ isinstance(self._backend, AcpConversation)
324
+ and result is not None
325
+ and result.failure is not None
326
+ and result.failure.error_class is ErrorClass.AGENT_TIMEOUT
327
+ ):
328
+ await self._retire_backend()
329
+
330
+ async def _run(
331
+ self, prompt: str, *, timeout: float | None, trajectory_context: TrajectoryContext | None
332
+ ) -> AgentAttemptResult:
333
+ """Execute one pass for *prompt*; a retry pass resumes what the failed pass left when it can."""
334
+ backend = self._backend
335
+ if backend is None:
336
+ raise RuntimeError("WorkflowAgentShell.run before open")
337
+ if self._run_task is not None and not self._run_task.done():
338
+ raise RuntimeError("an agent pass is already running for this activation")
339
+ if self._abort_cause is not None:
340
+ return AgentAttemptResult("cancelled")
341
+ self._prompt = prompt
342
+ if trajectory_context is not None:
343
+ trajectory_context = trajectory_context.with_actor(
344
+ workflow_node_actor(self._resources.session_id, self._invocation_id)
345
+ )
346
+ if isinstance(self._parts, KernelNodeParts):
347
+ self._parts.trace.context = trajectory_context
348
+ if isinstance(backend, AcpConversation):
349
+ backend.bind_trajectory(
350
+ trajectory_context,
351
+ boundary_operation_id=trajectory_context.innermost_model_operation_id
352
+ if trajectory_context is not None
353
+ else None,
354
+ )
355
+ if trajectory_context is not None and isinstance(self._parts, KernelNodeParts):
356
+ self._parts.run_kwargs["client_kwargs"] = {
357
+ **self._parts.run_kwargs.get("client_kwargs", {}),
358
+ TRAJECTORY_CONTEXT_KWARG: trajectory_context,
359
+ }
360
+ request = self._next_request(backend)
361
+ self._passes += 1
362
+ run_task = asyncio.create_task(self._pass(backend, request))
363
+ self._run_task = run_task
364
+ timed_out = False
365
+ try:
366
+ if timeout is None:
367
+ outcome = await run_task
368
+ else:
369
+ done, _pending = await asyncio.wait({run_task}, timeout=timeout)
370
+ if run_task not in done:
371
+ timed_out = True
372
+ await self.abort(AbortCause.CALLER_TIMEOUT)
373
+ done, _pending = await asyncio.wait({run_task}, timeout=ABORT_GRACE)
374
+ if run_task not in done:
375
+ run_task.cancel()
376
+ outcome = await run_task
377
+ except asyncio.CancelledError:
378
+ # The runner's attempt task was cancelled around us: converge the pass before leaving.
379
+ if self._abort_cause is None:
380
+ self._abort_cause = AbortCause.RUN_TERMINAL
381
+ backend.latch_abort(self._abort_cause)
382
+ run_task.cancel()
383
+ await asyncio.gather(run_task, return_exceptions=True)
384
+ raise
385
+ except (StaleContinuation, UnsupportedRequest, OverlappingRun, PreparedClosed) as exc:
386
+ self._ticket = None
387
+ return AgentAttemptResult(
388
+ "failed", failure=FailureReport(ErrorClass.AGENT_NON_TRANSIENT, f"{type(exc).__name__}: {exc}")
389
+ )
390
+ finally:
391
+ if timed_out and self._abort_cause is AbortCause.CALLER_TIMEOUT:
392
+ self._abort_cause = None # a timeout ends the pass, not the activation
393
+ return await self._project(outcome, timeout=timeout)
394
+
395
+ async def _pass(self, backend: KernelConversation | AcpConversation, request: RunRequest) -> InvocationOutcome:
396
+ """Run the pass marked as this shell's: the kernel's tasks for it inherit the mark with the context."""
397
+ _PASS_SHELL.set(self)
398
+ return await backend.run(request)
399
+
400
+ def holds(self, task: asyncio.Task[Any] | None) -> bool:
401
+ """True when *task* is the live pass or one started under it: the run waits for all of them.
402
+
403
+ The kernel runs the pass's attempt and each of its tool calls on tasks of its own, and the usage
404
+ callback schedules the progress publishes on others; an event published from any of them reaches
405
+ its subscribers on that task.
406
+ """
407
+ if task is None:
408
+ return False
409
+ return task is self._run_task or task.get_context().get(_PASS_SHELL) is self
410
+
411
+ def set_approval_mode(self, mode: ApprovalMode) -> None:
412
+ """Apply the engine's launch policy to the live pass's subsequent tool calls, sub-agents included."""
413
+ if isinstance(self._parts, KernelNodeParts):
414
+ self._parts.approval.set_approval_mode(mode)
415
+ if self._parts.sub_agent_tools is not None:
416
+ self._parts.sub_agent_tools.set_approval_mode(mode)
417
+
418
+ def _latch(self, cause: AbortCause) -> None:
419
+ if self._abort_cause is None or self._abort_cause not in _TERMINAL_CAUSES:
420
+ self._abort_cause = cause
421
+
422
+ async def abort(self, cause: AbortCause) -> None:
423
+ """Latch *cause* and converge the in-flight pass, if any, tearing its live sub-agents down first."""
424
+ self._latch(cause)
425
+ backend = self._backend
426
+ if backend is None:
427
+ return
428
+ if isinstance(self._parts, KernelNodeParts) and self._parts.sub_agent_tools is not None:
429
+ # Running children cancel their attempt, so long inner tool calls stop before the pass
430
+ # task itself is cancelled.
431
+ await self._parts.sub_agent_tools.cascade_abort_all()
432
+ backend.latch_abort(cause)
433
+ handle = backend.active_handle
434
+ if handle is not None:
435
+ await backend.abort(handle, cause)
436
+
437
+ # ------------------------------------------------------------------ OperationBinding
438
+
439
+ def request_close(self, cause: AbortCause) -> None:
440
+ self._latch(cause)
441
+ if self._backend is not None:
442
+ self._backend.latch_abort(cause)
443
+ if self._run_task is not None and not self._run_task.done():
444
+ self._run_task.cancel()
445
+
446
+ @property
447
+ def drained(self) -> Awaitable[None]:
448
+ return self._drain()
449
+
450
+ async def _drain(self) -> None:
451
+ task = self._run_task
452
+ if task is not None and not task.done():
453
+ await asyncio.gather(task, return_exceptions=True)
454
+
455
+ # ------------------------------------------------------------------ KernelPassObserver
456
+
457
+ async def begin(self, request: RunRequest, resources: PassResources) -> None:
458
+ parts = self._require_kernel_parts()
459
+ if request.intent is not RunIntent.FRESH and (not request.messages or self._has_live_continuation_token()):
460
+ # An admitted pass that continues retained work, or polls the response an earlier pass left
461
+ # running, carries the previous attempt's transcript on; the first fact of the attempt, so a
462
+ # presentation starts from that transcript.
463
+ await self._emitter.publish(
464
+ InvocationResumed(origin=request.origin, agent_name=self._display_name, session_id=self._session_id)
465
+ )
466
+ # Bound before the start hooks, which open the pass's hosted presentation under this origin.
467
+ parts.approval.bind_publisher(self._emitter)
468
+ parts.events.bind_origin(request.origin)
469
+ self._intermediate_buffer.drain()
470
+ self._pass_start_index = len(parts.history.messages())
471
+ resources.begin()
472
+ self._active_run_input = list(request.messages)
473
+ await self._save_transcript()
474
+
475
+ async def succeeded(self, response: AgentResponse[Any], /) -> None:
476
+ if isinstance(self._parts, KernelNodeParts):
477
+ await self._parts.events.reconcile_hosted_response(response.messages)
478
+
479
+ async def failed(self, error: Exception, /) -> None:
480
+ parts = self._require_kernel_parts()
481
+ parts.history.repair_after_failure(self._active_run_input, self._pass_start_index)
482
+ if self._abort_cause is None:
483
+ # An aborted pass can still end in an error; finished() settles its cards as interrupted.
484
+ await parts.events.reject_hosted_attempt(clean_error_message(error), status=HostedToolStatus.FAILED)
485
+
486
+ async def finished(self) -> None:
487
+ # A failed or interrupted pass publishes no outcome; its buffered text
488
+ # belongs to this pass's transcript, not the next one.
489
+ if isinstance(self._parts, KernelNodeParts):
490
+ await self._parts.events.finish_intermediate_text()
491
+ if self._abort_cause is not None:
492
+ # An aborted pass settles no hosted card; a resumed attempt would carry it on still running.
493
+ await self._parts.events.reject_hosted_attempt("Execution interrupted")
494
+
495
+ async def interrupt(self) -> None:
496
+ pass
497
+
498
+ def cancelled(self) -> None:
499
+ pass
500
+
501
+ # ------------------------------------------------------------------ construction
502
+
503
+ async def _open_conversation(self, conversation: Conversation) -> Conversation:
504
+ callbacks = AgentNodeCallbacks(
505
+ observer=self,
506
+ publish_intermediate=self._publish_intermediate,
507
+ checkpoint=self._mark_dirty,
508
+ usage=self._on_usage,
509
+ side_call_usage=self._on_side_call_usage,
510
+ validation_retry=self._publish_validation_retry,
511
+ wire_retry=self._publish_wire_retry,
512
+ service_retry=self._publish_service_retry,
513
+ interruptible_sleep=self._interruptible_sleep,
514
+ emitter=lambda: self._emitter,
515
+ acp_usage=self._on_acp_usage,
516
+ adopt_translator=self._adopt_acp_translator,
517
+ acp_counters=self._acp_counters,
518
+ )
519
+ if self._binding.agent.acp is not None:
520
+ self._parts = build_acp_node(
521
+ conversation,
522
+ binding=self._binding,
523
+ node_id=self._node_id,
524
+ invocation_id=self._invocation_id,
525
+ res=self._resources,
526
+ archive=self._archive,
527
+ callbacks=callbacks,
528
+ )
529
+ else:
530
+ self._parts = await build_kernel_node(
531
+ conversation,
532
+ binding=self._binding,
533
+ node_id=self._node_id,
534
+ invocation_id=self._invocation_id,
535
+ res=self._resources,
536
+ archive=self._archive,
537
+ callbacks=callbacks,
538
+ intermediate_buffer=self._intermediate_buffer,
539
+ stats=self._stats,
540
+ )
541
+ # Construction awaits sub-agent registration, MCP connection and skill discovery; a mode
542
+ # change that arrived meanwhile found no parts to apply to, so the launch policy is re-read.
543
+ self.set_approval_mode(self._resources.approval_mode())
544
+ return conversation
545
+
546
+ def _on_acp_usage(
547
+ self,
548
+ total: int,
549
+ input_tokens: int,
550
+ output_tokens: int,
551
+ local_tokens: int,
552
+ calibration_ratio: float,
553
+ system_overhead_tokens: int,
554
+ cache_hit_tokens: int | None,
555
+ max_context_tokens: int | None,
556
+ agent_profile: str,
557
+ usage_source_id: str,
558
+ total_usage_tokens: int,
559
+ ) -> None:
560
+ # ACP reports each transport once; the archive and graph summarize the whole activation.
561
+ self._usage_total += total_usage_tokens
562
+ self._stats.record_usage(total, self._usage_total)
563
+ self._resources.usage_publisher.accumulate_invocation_usage(
564
+ total,
565
+ input_tokens=input_tokens,
566
+ output_tokens=output_tokens,
567
+ local_tokens=local_tokens,
568
+ calibration_ratio=calibration_ratio,
569
+ system_overhead_tokens=system_overhead_tokens,
570
+ cache_hit_tokens=cache_hit_tokens,
571
+ max_context_tokens=max_context_tokens,
572
+ agent_profile=agent_profile,
573
+ usage_source_id=usage_source_id,
574
+ authoritative_total=total_usage_tokens,
575
+ )
576
+
577
+ # ------------------------------------------------------------------ passes
578
+
579
+ def _next_request(self, backend: KernelConversation | AcpConversation) -> RunRequest:
580
+ """Resume what the last pass left: its live ticket, its repaired history, or nothing after a success."""
581
+ ticket, self._ticket = self._ticket, None
582
+ if isinstance(backend, AcpConversation):
583
+ # Every ACP pass runs a new session from the prompt; a ticket only names the failed one.
584
+ return RunRequest(
585
+ self._seed_input(), RunIntent.RETRY if ticket is not None else RunIntent.FRESH, self.origin, ticket
586
+ )
587
+ history = self._require_kernel_parts().history
588
+ if ticket is not None and backend.continuation_is_live(ticket, self.origin):
589
+ return RunRequest(history.retry_input(self._seed_input), RunIntent.RETRY, self.origin, ticket)
590
+ if self._resume:
591
+ return RunRequest(history.retry_input(self._seed_input), RunIntent.CONTINUE, self.origin, None)
592
+ # A completed body is run again from the prompt when a later phase of its attempt failed.
593
+ self._drop_continuation_token()
594
+ if self._passes:
595
+ backend.history_state = {} # a fresh pass starts from the prompt, not from a stale transcript
596
+ return RunRequest(self._seed_input(), RunIntent.FRESH, self.origin, None)
597
+
598
+ async def _project(self, outcome: InvocationOutcome, *, timeout: float | None) -> AgentAttemptResult:
599
+ self._evidence = self._evidence.add(outcome.effects)
600
+ self._resume = False
601
+ if isinstance(outcome, Ok):
602
+ self._ticket = None
603
+ if isinstance(outcome.backend_payload, AgentResponse):
604
+ # The node's value is the final segment, as a sub-agent's result is; what the agent wrote
605
+ # between tool calls is already in the transcript.
606
+ segment = FinalSegment.of(outcome.backend_payload)
607
+ value, transcript = segment.result, segment.transcript
608
+ else:
609
+ # An ACP result is left alone, since the profile's result mode already chose its extent.
610
+ value = transcript = _response_text(outcome)
611
+ if isinstance(self._backend, AcpConversation) and self._backend.transcript_final_text is not None:
612
+ transcript = self._backend.transcript_final_text
613
+ await self._emitter.publish(
614
+ InvocationMessage(
615
+ origin=self.origin,
616
+ agent_name=self._display_name,
617
+ text=transcript,
618
+ is_final=True,
619
+ session_id=self._session_id,
620
+ )
621
+ )
622
+ return AgentAttemptResult("completed", text=value)
623
+ if isinstance(outcome, Failed):
624
+ self._ticket = outcome.continuation
625
+ self._resume = isinstance(self._parts, KernelNodeParts)
626
+ transient = self._retryable(outcome)
627
+ approved = transient and not self._repeats_hosted_work(outcome, outcome.exception)
628
+ error_class = ErrorClass.AGENT_TRANSIENT if transient else ErrorClass.AGENT_NON_TRANSIENT
629
+ return AgentAttemptResult(
630
+ "failed", failure=FailureReport(error_class, outcome.error, backend_approved=approved)
631
+ )
632
+ if not isinstance(outcome, Aborted):
633
+ raise TypeError("Expected an aborted agent outcome after handling success and failure.")
634
+ self._ticket = None
635
+ # An aborted request is abandoned, never polled again: its retry creates a new one. A response
636
+ # still running at the provider may yet run hosted tools that the new request would repeat.
637
+ abandoned_response = self._has_live_continuation_token()
638
+ self._drop_continuation_token()
639
+ if outcome.cause is AbortCause.CALLER_TIMEOUT:
640
+ if isinstance(self._parts, KernelNodeParts):
641
+ # The deadline cut the pass off before its history was saved: keep the completed tool
642
+ # work, so the next attempt continues after it instead of running it again.
643
+ self._parts.history.repair_after_failure(self._active_run_input, self._pass_start_index)
644
+ self._resume = True
645
+ limit = f"{timeout:g}s" if timeout is not None else "its deadline"
646
+ return AgentAttemptResult(
647
+ "failed",
648
+ failure=FailureReport(
649
+ ErrorClass.AGENT_TIMEOUT,
650
+ f"no response within {limit}",
651
+ backend_approved=not abandoned_response and not self._repeats_hosted_work(outcome, None),
652
+ ),
653
+ )
654
+ return AgentAttemptResult("cancelled")
655
+
656
+ def _retryable(self, outcome: Failed) -> bool:
657
+ """Whether repeating the failed pass can succeed: a clear refusal, quota or configuration error cannot."""
658
+ if outcome.category is not FailureCategory.UNCLASSIFIED:
659
+ return outcome.category in _RETRYABLE_ACP_CATEGORIES
660
+ exception = outcome.exception
661
+ if exception is None:
662
+ return False
663
+ # A stall already outlasted the in-pass retries; a later attempt may find the stream moving again.
664
+ return is_retryable(exception) or classify_error(exception).kind is ErrorKind.STREAM_STALLED
665
+
666
+ def _repeats_hosted_work(self, outcome: Failed | Aborted, exception: Exception | None) -> bool:
667
+ """Whether resuming would run provider-hosted tool calls a second time.
668
+
669
+ Resumed history keeps every completed exchange, so only the last request's hosted work is at risk
670
+ — named by its validation error, or by the middleware's probe unless the repaired history kept the
671
+ response that ran it. Under service-side storage the history may hold none of the pass, so any hosted
672
+ work of the pass counts. A live continuation token makes the retry a poll of the response already
673
+ created.
674
+ """
675
+ parts = self._parts
676
+ if not isinstance(parts, KernelNodeParts) or self._has_live_continuation_token():
677
+ return False
678
+ if exception is not None and hosted_commits_from_error(exception):
679
+ return True
680
+ if parts.backend.service_session_storage_enabled:
681
+ return outcome.effects.hosted_observed.observed > 0
682
+ return bool(parts.hosted_unkept(parts.history.messages()[self._pass_start_index :]))
683
+
684
+ def _has_live_continuation_token(self) -> bool:
685
+ return isinstance(self._parts, KernelNodeParts) and has_live_continuation_token(self._parts.run_kwargs)
686
+
687
+ def _drop_continuation_token(self) -> None:
688
+ if isinstance(self._parts, KernelNodeParts):
689
+ drop_continuation_token(self._parts.run_kwargs)
690
+
691
+ async def _interruptible_sleep(self, seconds: int) -> bool:
692
+ for _ in range(max(0, seconds)):
693
+ if self._abort_cause is not None:
694
+ return True
695
+ await asyncio.sleep(1)
696
+ return self._abort_cause is not None
697
+
698
+ # ------------------------------------------------------------------ history
699
+
700
+ def _require_checkpoint(self) -> CoalescedCheckpoint:
701
+ if self._checkpoint is None:
702
+ raise RuntimeError("The agent node checkpoint has not been opened.")
703
+ return self._checkpoint
704
+
705
+ def _require_kernel_parts(self) -> KernelNodeParts:
706
+ if not isinstance(self._parts, KernelNodeParts):
707
+ raise TypeError("A kernel agent pass requires kernel node resources.")
708
+ return self._parts
709
+
710
+ async def _mark_dirty(self) -> None:
711
+ self._require_checkpoint().changed()
712
+
713
+ async def _adopt_acp_translator(self, translator: AcpUpdateTranslator) -> None:
714
+ self._acp_translators.append(translator)
715
+ if self._checkpoint is not None:
716
+ translator.on_audit_changed = self._checkpoint.changed
717
+ await self._save_transcript()
718
+
719
+ async def _save_transcript(self, *, status: str = "running", error: str = "") -> None:
720
+ state = None
721
+ acp_state = None
722
+ if isinstance(self._backend, AcpConversation):
723
+ acp_state = {
724
+ "prompt": self._user_prompt(self._prompt),
725
+ "translated_updates": [
726
+ {**item, "attempt": translator.attempt}
727
+ for translator in self._acp_translators
728
+ for item in translator.translated_updates
729
+ ],
730
+ "successful_attempt": self._backend.transport_ordinal if status == "completed" else None,
731
+ }
732
+ self._stats.tool_call_count = max(
733
+ (self._backend.completed_tool_calls, *(t.completed_count for t in self._acp_translators))
734
+ )
735
+ self._stats.usage_unreported_attempts = self._backend.usage_unreported_attempts
736
+ elif isinstance(self._parts, KernelNodeParts):
737
+ # Keep message identities while merging into a detached list. This
738
+ # reuses the same recovery merge as Chat without mutating the
739
+ # active model history or deduplicating repeated provider call IDs.
740
+ state = dict(self._parts.history.state())
741
+ state["messages"] = list(state.get("messages", []))
742
+ input_message = active_input_message(self._active_run_input)
743
+ if not state["messages"] and input_message is not None:
744
+ state["messages"].append(input_message)
745
+ manager = SessionHistoryManager()
746
+ manager.bind(state)
747
+ manager.merge_loop_messages(self._parts.history.recorder, insert_index=self._pass_start_index)
748
+ stamp_history_item_ids(state)
749
+ await self._archive.write(
750
+ attempt=self._archive_attempt,
751
+ status=status,
752
+ error=error,
753
+ state=state,
754
+ acp_state=acp_state,
755
+ stats=self._stats,
756
+ )
757
+ if status != "running" and isinstance(self._parts, KernelNodeParts) and self._parts.sub_agent_tools is not None:
758
+ # Children's control records go once the attempt's terminal transcript is on disk, as after
759
+ # a chat turn's save; a running checkpoint is best-effort and may predate a child's result.
760
+ self._parts.sub_agent_tools.finalize_pending_cleanups()
761
+
762
+ def _user_prompt(self, prompt: str) -> str:
763
+ """The same user text feeds the conversation and its live presentation."""
764
+ if self._binding.agent.acp is not None and self._binding.instructions_suffix:
765
+ return f"{prompt}\n\n{self._binding.instructions_suffix}"
766
+ return prompt
767
+
768
+ def _seed_input(self) -> list[Any]:
769
+ message = Message("user", [self._user_prompt(self._prompt)])
770
+ ensure_analytics_item_id(message.additional_properties, item_id=self._seed_item_id)
771
+ return [message]
772
+
773
+ # ------------------------------------------------------------------ events
774
+
775
+ @property
776
+ def _session_id(self) -> str | None:
777
+ return self._resources.session_id or None
778
+
779
+ async def _publish_intermediate(self, text: str) -> None:
780
+ self._intermediate_buffer.new_batch()
781
+ await self._emitter.publish(
782
+ InvocationMessage(
783
+ origin=self.origin,
784
+ agent_name=self._display_name,
785
+ text=text,
786
+ is_final=False,
787
+ is_intermediate=True,
788
+ session_id=self._session_id,
789
+ )
790
+ )
791
+
792
+ async def _publish_validation_retry(self, info: RetryAttemptInfo) -> None:
793
+ await self._emitter.publish(
794
+ InvocationRetryAttempt(
795
+ scope="wire",
796
+ origin=self.origin,
797
+ agent_name=self._display_name,
798
+ message=f"Invalid response: {info.reason}",
799
+ attempt=info.attempt,
800
+ max_attempts=info.max_attempts,
801
+ delay_seconds=int(info.delay_seconds),
802
+ session_id=self._session_id,
803
+ )
804
+ )
805
+
806
+ async def _publish_wire_retry(
807
+ self, message: str, attempt: int, max_attempts: int, delay_seconds: int, exc: BaseException
808
+ ) -> None:
809
+ await self._publish_retry(message, attempt, max_attempts, delay_seconds, exc, scope="wire")
810
+
811
+ async def _publish_service_retry(
812
+ self, message: str, attempt: int, max_attempts: int, delay_seconds: int, exc: BaseException
813
+ ) -> None:
814
+ await self._publish_retry(message, attempt, max_attempts, delay_seconds, exc, scope="run")
815
+
816
+ async def _publish_retry(
817
+ self,
818
+ message: str,
819
+ attempt: int,
820
+ max_attempts: int,
821
+ delay_seconds: int,
822
+ exc: BaseException,
823
+ *,
824
+ scope: Literal["wire", "run"],
825
+ ) -> None:
826
+ emitter = self._emitter
827
+ if isinstance(self._parts, KernelNodeParts) and not self._has_live_continuation_token():
828
+ # The retried request's hosted cards will not finish; a poll of a created response still may.
829
+ await self._parts.events.reject_hosted_attempt(message)
830
+ display_message, display_hint = display_fields(exc, retry_notice=True)
831
+ await emitter.publish(
832
+ InvocationRetryAttempt(
833
+ scope=scope,
834
+ origin=emitter.origin,
835
+ agent_name=self._display_name,
836
+ message=message,
837
+ attempt=attempt,
838
+ max_attempts=max_attempts,
839
+ delay_seconds=delay_seconds,
840
+ session_id=self._session_id,
841
+ display_message=display_message,
842
+ display_hint=display_hint,
843
+ )
844
+ )
845
+
846
+ def _on_side_call_usage(self, usage_details: Mapping[str, Any]) -> None:
847
+ """Charge summary generation to this node without replacing its context-window reading."""
848
+ self._resources.usage_publisher.accumulate_side_call_usage(
849
+ usage_details,
850
+ agent_profile=self._binding.agent.name,
851
+ usage_source_id=f"{self._invocation_id}:last_words",
852
+ max_context_tokens=self._binding.model.max_context_tokens if self._binding.model is not None else None,
853
+ )
854
+ self._usage_total += int(usage_details.get("total_token_count") or 0)
855
+ if isinstance(self._parts, KernelNodeParts):
856
+ self._parts.events.record_usage(self._stats.total_tokens, self._usage_total)
857
+
858
+ # Positional args mirror UsageTrackingMiddleware._fire_callback. New fields must be named and
859
+ # forwarded here as well: *_rest tolerates extra arguments but does not account for their values.
860
+ def _on_usage(
861
+ self,
862
+ total: int,
863
+ input_tokens: int = 0,
864
+ output_tokens: int = 0,
865
+ local_tokens: int = 0,
866
+ calibration_ratio: float = 1.0,
867
+ system_overhead_tokens: int = 0,
868
+ cache_hit_tokens: int | None = None,
869
+ _calibration_initialized: bool = False,
870
+ use_local_context_estimate: bool = False,
871
+ *_rest: Any,
872
+ ) -> None:
873
+ self._usage_total += total
874
+ if isinstance(self._parts, KernelNodeParts):
875
+ self._parts.events.record_usage(total, self._usage_total)
876
+ self._resources.usage_publisher.accumulate_invocation_usage(
877
+ total,
878
+ input_tokens=input_tokens,
879
+ output_tokens=output_tokens,
880
+ local_tokens=local_tokens,
881
+ calibration_ratio=calibration_ratio,
882
+ system_overhead_tokens=system_overhead_tokens,
883
+ cache_hit_tokens=cache_hit_tokens,
884
+ max_context_tokens=self._binding.model.max_context_tokens if self._binding.model is not None else None,
885
+ agent_profile=self._binding.agent.name,
886
+ usage_source_id=self._invocation_id,
887
+ use_local_context_estimate=use_local_context_estimate,
888
+ )
889
+
890
+
891
+ def _response_text(outcome: Ok) -> str:
892
+ return "".join(
893
+ segment.text for segment in outcome.segments if segment.type == "text" and isinstance(segment.text, str)
894
+ ).strip()