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,1061 @@
1
+ # Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
2
+
3
+ """AgentBuilder — constructs Agent + TurnBindings from an AgentProfile.
4
+
5
+ Extracts the infrastructure-wiring logic from ``AgentEngine._build_agent``
6
+ into a reusable function. The engine provides callbacks (for intermediate
7
+ text, usage, injection) that close over engine state; this module handles
8
+ everything else: compaction strategy, context management, tool loading,
9
+ sub-agent registration, skills, middleware chain, and Agent/TurnBindings creation.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ from collections.abc import Awaitable, Callable, Mapping
16
+ from dataclasses import asdict, dataclass
17
+ from functools import partial
18
+ from pathlib import Path
19
+ from typing import TYPE_CHECKING, Any, Literal, Protocol
20
+
21
+ from chrys.foundation.config.settings import Settings
22
+ from chrys.foundation.events.types import (
23
+ AGENT_LOAD_PHASE_AGENT,
24
+ AGENT_LOAD_PHASE_MCP,
25
+ AGENT_LOAD_PHASE_MODEL,
26
+ AGENT_LOAD_PHASE_RUNTIME,
27
+ AGENT_LOAD_PHASE_SKILLS,
28
+ AGENT_LOAD_PHASE_SUB_AGENTS,
29
+ AGENT_LOAD_PHASE_TOOLS,
30
+ AGENT_LOAD_STATUS_DONE,
31
+ AGENT_LOAD_STATUS_FAILED,
32
+ AGENT_LOAD_STATUS_RUNNING,
33
+ AGENT_LOAD_STATUS_SKIPPED,
34
+ AgentRuntimeDetails,
35
+ CompactionFinished,
36
+ CompactionStarted,
37
+ InvocationContextPressure,
38
+ InvocationMessage,
39
+ InvocationRetryAttempt,
40
+ RuntimeHookDetails,
41
+ RuntimeHookSourceDetails,
42
+ RuntimeModelDetails,
43
+ Warning,
44
+ )
45
+ from chrys.foundation.i18n import DisplayBlock, msg
46
+ from chrys.foundation.models.session_env import SessionEnvironment
47
+ from chrys.foundation.platform.files import surrogate_safe_text
48
+ from chrys.foundation.retry import RetryAttemptInfo
49
+ from chrys.foundation.tool_kinds import KIND_ASK_USER, KIND_FILESYSTEM_READ, KIND_SHELL, get_tool_kind
50
+ from chrys.kernel import Agent, LoopRecorder
51
+ from chrys.orchestration.engine.run.bindings import TurnBindings
52
+ from chrys.orchestration.invoker.origin import InvocationPublishers
53
+ from chrys.orchestration.invoker.resources import Conversation, PreparedAgent, rollback_resources
54
+ from chrys.orchestration.invoker.runtime import (
55
+ ApprovalInputs,
56
+ AskUserInputs,
57
+ ContextInputs,
58
+ LastWordsInputs,
59
+ MainRecipe,
60
+ ReminderInputs,
61
+ SharedRuntime,
62
+ create_approval,
63
+ create_ask_user,
64
+ create_context,
65
+ create_runtime,
66
+ create_validation,
67
+ )
68
+ from chrys.orchestration.sub_agents.registration import (
69
+ acp_sub_agent_depth,
70
+ sub_agent_registration_state,
71
+ sub_agent_skip_reason,
72
+ )
73
+ from chrys.service.agent_middleware import (
74
+ IntermediateTextBuffer,
75
+ TodoMiddleware,
76
+ )
77
+ from chrys.service.agent_middleware.injection import InjectionMiddleware
78
+ from chrys.service.agent_middleware.system_reminder import SystemReminderMiddleware
79
+ from chrys.service.approval.policy import ApprovalMode, ApprovalPolicy
80
+ from chrys.service.approval.reuse_binding import ApprovalReuseBinding
81
+ from chrys.service.context.compaction.last_words_state import DropRoundBreakerState, LastWordsState
82
+ from chrys.service.context.compaction.spill import COMPACTIONS_DIR_NAME
83
+ from chrys.service.context.memory_loader import load_memory_content, memory_truncated_warning
84
+ from chrys.service.llm.clients import create_client, effective_model_base_url
85
+ from chrys.service.llm.route_sessions import derive_llm_route_session_id
86
+ from chrys.service.profiles.models.options import (
87
+ effective_chat_options,
88
+ protected_chat_option_keys_warning_structured,
89
+ uses_responses_compact_continuation,
90
+ )
91
+ from chrys.service.profiles.models.resolver import resolve_selection_for_agent
92
+ from chrys.service.profiles.models.schema import API_STYLE_CHAT_COMPLETIONS, API_STYLE_RESPONSES
93
+ from chrys.service.session.persistence import agent_profile_context_fingerprint, model_profile_context_fingerprint
94
+ from chrys.service.state.serializers import serialized_message_payload
95
+ from chrys.service.todos.reminder import format_todo_reminder
96
+ from chrys.service.tools.names import chrys_reserved_tool_names
97
+
98
+ if TYPE_CHECKING:
99
+ from chrys.foundation.events.bus import EventBus
100
+ from chrys.foundation.models.workspace import Workspace
101
+ from chrys.orchestration.sub_agents.tools import SubAgentTools
102
+ from chrys.service.approval.judge import ApprovalJudge
103
+ from chrys.service.approval.turn_context import TurnContextHolder
104
+ from chrys.service.context.compaction import CompactionInfo, CompressInfo, PreCompactInfo
105
+ from chrys.service.context.compaction.last_words import CompactionStatus
106
+ from chrys.service.context.compaction.spill import SpillQuota
107
+ from chrys.service.hooks.manager import HookManager
108
+ from chrys.service.hooks.schema import HooksFile
109
+ from chrys.service.mcp.adapter import MCPAdapter
110
+ from chrys.service.mcp.cache import MCPConnectionCache
111
+ from chrys.service.mutations.coordination import MutationCoordinator
112
+ from chrys.service.mutations.tracker import MutationTracker
113
+ from chrys.service.profiles.agents.registry import AgentProfileRegistry
114
+ from chrys.service.profiles.agents.schema import AgentProfile
115
+ from chrys.service.profiles.models.registry import ModelProfileRegistry
116
+ from chrys.service.profiles.models.schema import ModelProfile
117
+ from chrys.service.skills.provider import ChrysSkillsProvider
118
+ from chrys.service.todos.tracker import TodoTracker
119
+
120
+ logger = logging.getLogger(__name__)
121
+
122
+ _RETRY_LAST_WORDS_COMPACTION = msg(
123
+ "retry.last_words_compaction",
124
+ fallback="LAST_WORDS compaction: {reason}",
125
+ multiline=True,
126
+ )
127
+ _RETRY_INVALID_RESPONSE = msg(
128
+ "retry.invalid_response",
129
+ fallback="Invalid response: {reason}",
130
+ multiline=True,
131
+ )
132
+ _BUILDER_PROTECTED_CHAT_OPTIONS_STRIPPED = msg(
133
+ "builder.protected_chat_options_stripped",
134
+ fallback=(
135
+ "Protected chat option key(s) were stripped: {keys}. "
136
+ "These keys can no longer be configured in profile YAML because they bypass context admission. "
137
+ "Reusable prompts and profile-pinned continuation IDs are unavailable there; store: true only enables "
138
+ "automatically managed Responses continuation."
139
+ ),
140
+ )
141
+
142
+
143
+ def _render_todo_reminder(tracker: TodoTracker | None) -> str | None:
144
+ """Todo reminder provider body — reads the sync lock-free tracker snapshot."""
145
+ if tracker is None:
146
+ return None
147
+ return format_todo_reminder(tracker.snapshot())
148
+
149
+
150
+ def _runtime_api_style(provider: str, api_style: str) -> str:
151
+ """Return the API style users should see for the active model transport."""
152
+ if provider in ("openai", "deepseek-openai"):
153
+ return api_style
154
+ if provider == "glm-openai":
155
+ return API_STYLE_CHAT_COMPLETIONS
156
+ return ""
157
+
158
+
159
+ def _runtime_hook_source_details(
160
+ scope: Literal["project", "global"],
161
+ file: HooksFile,
162
+ ) -> RuntimeHookSourceDetails:
163
+ """Build the non-sensitive runtime view for one hook config source."""
164
+ return RuntimeHookSourceDetails(
165
+ scope=scope,
166
+ source_path=surrogate_safe_text(file.source),
167
+ hooks=[
168
+ RuntimeHookDetails(
169
+ id=hook.id,
170
+ event=str(hook.event),
171
+ execution_mode=hook.execution.mode,
172
+ enabled=hook.enabled,
173
+ description=hook.description,
174
+ )
175
+ for hook in file.hooks
176
+ ],
177
+ )
178
+
179
+
180
+ def _runtime_hook_sources(hook_manager: HookManager | None) -> list[RuntimeHookSourceDetails]:
181
+ """Snapshot the live project/global hook manager without executable configuration."""
182
+ if hook_manager is None:
183
+ return []
184
+ sources: list[RuntimeHookSourceDetails] = []
185
+ project = hook_manager.file.project
186
+ if project is not None:
187
+ sources.append(_runtime_hook_source_details("project", project))
188
+ global_ = hook_manager.file.global_
189
+ if global_ is not None:
190
+ sources.append(_runtime_hook_source_details("global", global_))
191
+ return sources
192
+
193
+
194
+ class LoadProgressCallback(Protocol):
195
+ """Typed callback used by the engine to surface build progress."""
196
+
197
+ def __call__(
198
+ self,
199
+ *,
200
+ phase: str,
201
+ message: str,
202
+ server_name: str = "",
203
+ current: int = 0,
204
+ total: int = 0,
205
+ failed: int = 0,
206
+ status: str = "",
207
+ subject: str = "",
208
+ detail: str = "",
209
+ ) -> Awaitable[None]: ...
210
+
211
+
212
+ @dataclass
213
+ class AgentBuildResult:
214
+ """Everything produced by ``build_agent``."""
215
+
216
+ prepared: PreparedAgent
217
+ conversation: Conversation
218
+ agent: Agent
219
+ bindings: TurnBindings
220
+ runtime: SessionEnvironment
221
+ loop_recorder: LoopRecorder
222
+ reminder_middleware: SystemReminderMiddleware
223
+ last_words: LastWordsState
224
+ sub_agent_tools: SubAgentTools | None
225
+ mcp_adapter: MCPAdapter | None
226
+ skills_provider: ChrysSkillsProvider | None
227
+ tool_names: list[str]
228
+ tool_kinds: dict[str, str]
229
+ skill_names: list[str]
230
+ memory_files: list[str]
231
+ agent_profile_fingerprint: str
232
+ model_profile_fingerprint: str
233
+ runtime_details: AgentRuntimeDetails
234
+ compaction_strategy: Any
235
+ active_profile: ModelProfile
236
+
237
+
238
+ async def build_agent(
239
+ # -- required -----------------------------------------------------
240
+ profile: AgentProfile,
241
+ settings: Settings,
242
+ workspace: Workspace | None,
243
+ session_id: str | None,
244
+ bus: EventBus,
245
+ agent_registry: AgentProfileRegistry | None,
246
+ injection: InjectionMiddleware,
247
+ intermediate_buffer: IntermediateTextBuffer,
248
+ on_intermediate_async: Callable[[str], Awaitable[None]],
249
+ on_intermediate_sync: Callable[[str], None],
250
+ on_usage: Callable[..., None],
251
+ *,
252
+ # -- optional -----------------------------------------------------
253
+ model_registry: ModelProfileRegistry | None = None,
254
+ on_sub_agent_usage: Callable[..., None] | None = None,
255
+ on_side_call_usage: Callable[[Mapping[str, Any]], None] | None = None,
256
+ commit_intermediate_text: Callable[[str, int], None] | None = None,
257
+ drain_parent_usage_publishes: Callable[[], Awaitable[None]] | None = None,
258
+ on_compaction: Callable[[CompactionInfo], Awaitable[None]] | None = None,
259
+ on_pre_compact: Callable[[PreCompactInfo], Awaitable[None]] | None = None,
260
+ on_compress: Callable[[CompressInfo], Awaitable[None]] | None = None,
261
+ on_load_progress: LoadProgressCallback | None = None,
262
+ mutation_tracker: MutationTracker | None = None,
263
+ mutation_coordinator: MutationCoordinator | None = None,
264
+ todo_tracker: TodoTracker | None = None,
265
+ file_change_provider: Callable[[], str | None] | None = None,
266
+ approval_mode: ApprovalMode = ApprovalMode.MANUAL,
267
+ approval_judge: ApprovalJudge | None = None,
268
+ session_dir: Path | None = None,
269
+ mcp_cache: MCPConnectionCache | None = None,
270
+ hook_manager: HookManager | None = None,
271
+ spill_quota: SpillQuota | None = None,
272
+ persist_recovery_now: Callable[[], Awaitable[bool]] | None = None,
273
+ turn_context: TurnContextHolder | None = None,
274
+ allow_user_interaction: bool = True,
275
+ ) -> AgentBuildResult:
276
+ """Build an ``Agent``, ``TurnBindings``, and all supporting infrastructure.
277
+
278
+ Parameters
279
+ ----------
280
+ profile:
281
+ The agent profile to build from. Explicit main-agent model overrides
282
+ in ``settings`` win first; otherwise the profile's ``model.profile_id``
283
+ (if set and registered) overrides the session-active profile.
284
+ settings:
285
+ Application settings — provides the session-active model profile
286
+ id via ``settings.model_profile``.
287
+ model_registry:
288
+ Registry used to resolve the main agent's ``profile_id``
289
+ override and per-sub-agent overrides. ``None`` → everything
290
+ falls back to the hardcoded default profile.
291
+ workspace:
292
+ Current workspace (used for ``SessionEnvironment``).
293
+ session_id:
294
+ Current session ID (passed to ``TurnBindings``).
295
+ bus:
296
+ Event bus (passed to ``TurnBindings``).
297
+ agent_registry:
298
+ Profile registry (used for sub-agent resolution).
299
+ injection:
300
+ Pre-configured ``InjectionMiddleware`` (engine owns the callbacks).
301
+ intermediate_buffer:
302
+ Pre-configured ``IntermediateTextBuffer``.
303
+ on_intermediate_async:
304
+ Async callback for intermediate text (non-streaming path).
305
+ on_intermediate_sync:
306
+ Sync callback for intermediate text (streaming path).
307
+ commit_intermediate_text:
308
+ Accepted-only persistence callback for a pre-reserved provisional batch.
309
+ on_usage:
310
+ Callback for context usage updates.
311
+ on_side_call_usage:
312
+ Callback receiving raw provider ``usage_details`` from Phase-4
313
+ LAST_WORDS side calls (main agent and sub-agents) so their spend
314
+ joins the session totals.
315
+ on_compaction:
316
+ Callback for intra-turn tool compaction events.
317
+
318
+ Returns
319
+ -------
320
+ AgentBuildResult
321
+ All constructed components needed by the engine.
322
+ """
323
+
324
+ prepared = PreparedAgent()
325
+
326
+ async def _acquire(conversation: Conversation) -> AgentBuildResult:
327
+ nonlocal turn_context
328
+
329
+ async def _progress(
330
+ phase: str,
331
+ message: str,
332
+ *,
333
+ server_name: str = "",
334
+ current: int = 0,
335
+ total: int = 0,
336
+ failed: int = 0,
337
+ status: str = "",
338
+ subject: str = "",
339
+ detail: str = "",
340
+ ) -> None:
341
+ if on_load_progress is not None:
342
+ await on_load_progress(
343
+ phase=phase,
344
+ message=message,
345
+ server_name=server_name,
346
+ current=current,
347
+ total=total,
348
+ failed=failed,
349
+ status=status,
350
+ subject=subject,
351
+ detail=detail,
352
+ )
353
+
354
+ if profile.acp is not None:
355
+ raise ValueError(f"ACP profile {profile.name!r} is sub-agent-only and cannot be launched as the main agent")
356
+
357
+ transient_retries = settings.effective_max_transient_retries()
358
+
359
+ if turn_context is None:
360
+ from chrys.service.approval.turn_context import TurnContextHolder
361
+
362
+ turn_context = TurnContextHolder()
363
+
364
+ await _progress(AGENT_LOAD_PHASE_MODEL, "Resolving model profile", status=AGENT_LOAD_STATUS_RUNNING)
365
+
366
+ # Resolve the main agent's ModelProfile: profile override → active.
367
+ # Missing ids fall back silently to active (no throw).
368
+ model_selection = resolve_selection_for_agent(model_registry, settings, profile)
369
+ active_profile = model_selection.profile
370
+
371
+ # Capture the session environment for this agent build.
372
+ await _progress(AGENT_LOAD_PHASE_RUNTIME, "Capturing workspace context", status=AGENT_LOAD_STATUS_RUNNING)
373
+ runtime = SessionEnvironment.capture(workspace=workspace)
374
+ serialize_implicit_windows = not settings.parallel_implicit_tools
375
+
376
+ # Auto-loaded memory (files + folders configured on the profile). Read
377
+ # once per build; subsequent edits to source files are picked up by the
378
+ # next build (e.g. profile-save soft-restart). Sub-agents skip this by
379
+ # not passing ``memory_text`` on their own ContextManager.
380
+ memory_content = load_memory_content(
381
+ profile.memory,
382
+ workspace_cwd=workspace.primary_cwd if workspace else None,
383
+ )
384
+ acp_depth = acp_sub_agent_depth()
385
+ effective_sub_agents: list[dict[str, Any]] = []
386
+ for ref in profile.sub_agents.agents:
387
+ resolved = agent_registry.get(ref.profile) if agent_registry is not None else None
388
+ effective_sub_agents.append(
389
+ {
390
+ "reference": asdict(ref),
391
+ "resolved_profile": asdict(resolved) if resolved is not None else None,
392
+ "state": sub_agent_registration_state(resolved, acp_depth=acp_depth),
393
+ }
394
+ )
395
+ agent_profile_fingerprint = agent_profile_context_fingerprint(
396
+ profile,
397
+ memory_text=memory_content.text,
398
+ effective_sub_agents=effective_sub_agents,
399
+ allow_user_interaction=allow_user_interaction,
400
+ )
401
+
402
+ # Resolve session-scoped log directories from a single session_dir source.
403
+ # If the caller didn't pass session_dir (e.g. engine with no state_store)
404
+ # but a session_id exists, fall back to the active sessions directory — this
405
+ # preserves on-disk logging for real runs. Tests with ``tmp_path`` stores
406
+ # always pass session_dir, so their logs stay in the temp dir.
407
+ effective_session_dir = session_dir
408
+ if effective_session_dir is None and session_id:
409
+ from chrys.foundation.config.settings import resolve_sessions_dir
410
+ from chrys.foundation.util.session_ids import session_short_id
411
+
412
+ effective_session_dir = resolve_sessions_dir() / session_short_id(session_id)
413
+ approval_log_dir = effective_session_dir / "approvals" if effective_session_dir else None
414
+ last_words_log_dir = effective_session_dir / "compactions" / "debug" if effective_session_dir else None
415
+
416
+ # Parse chat options early — needed by context history mode, executor, and sub-agents.
417
+ chat_options = effective_chat_options(active_profile)
418
+ if protected_options_warning := protected_chat_option_keys_warning_structured(active_profile):
419
+ await bus.publish(
420
+ Warning(
421
+ code="protected_chat_options_stripped",
422
+ message=protected_options_warning.message,
423
+ display_message=_BUILDER_PROTECTED_CHAT_OPTIONS_STRIPPED.bind(
424
+ keys=", ".join(protected_options_warning.keys)
425
+ ),
426
+ session_id=session_id,
427
+ )
428
+ )
429
+ model_profile_fingerprint = model_profile_context_fingerprint(active_profile, chat_options=chat_options)
430
+ uses_responses_service_history = (
431
+ active_profile.provider == "openai" and active_profile.api_style == API_STYLE_RESPONSES
432
+ )
433
+ capture_service_loop_messages = uses_responses_compact_continuation(active_profile, chat_options)
434
+ context_recall_session_id = derive_llm_route_session_id(
435
+ session_id,
436
+ route_kind="context-recall",
437
+ model_profile=active_profile,
438
+ )
439
+ last_words_session_id = derive_llm_route_session_id(
440
+ session_id,
441
+ route_kind="last-words",
442
+ route_parts=(profile.name,),
443
+ model_profile=active_profile,
444
+ )
445
+
446
+ def _publish_context_pressure(
447
+ reason: str,
448
+ breaker: DropRoundBreakerState,
449
+ budget: int,
450
+ ) -> Awaitable[None]:
451
+ emitter = invocation_publishers.capture()
452
+ return emitter.publish(
453
+ InvocationContextPressure(
454
+ origin=emitter.origin,
455
+ reason=reason,
456
+ attempts=breaker.attempts,
457
+ side_call_tokens=breaker.side_call_tokens,
458
+ side_call_token_budget=budget,
459
+ session_id=session_id,
460
+ )
461
+ )
462
+
463
+ # Context management (providers + middleware + compaction from profile config)
464
+ context_inputs = ContextInputs(
465
+ profile=active_profile,
466
+ on_usage=on_usage,
467
+ on_compaction=on_compaction,
468
+ on_pre_compact=on_pre_compact,
469
+ on_compress=on_compress,
470
+ on_context_pressure=_publish_context_pressure,
471
+ spill_quota=spill_quota,
472
+ debug_log_dir=last_words_log_dir,
473
+ compaction_config=profile.compaction,
474
+ memory_text=memory_content.text,
475
+ warn_threshold_pct=settings.warn_threshold_pct,
476
+ session_id=context_recall_session_id,
477
+ parent_session_id=session_id,
478
+ session_dir=effective_session_dir,
479
+ skip_local_history_for_service_context=uses_responses_service_history,
480
+ service_context_default_options=chat_options,
481
+ )
482
+
483
+ ctx = create_context(context_inputs)
484
+
485
+ # Create LLM client with intermediate text callbacks. ``session_dir`` is
486
+ # only used by opt-in raw HTTP logging; normal transport construction stays
487
+ # unchanged.
488
+ invocation_publishers = InvocationPublishers(bus)
489
+
490
+ async def _publish_intermediate(text: str) -> None:
491
+ emitter = invocation_publishers.capture()
492
+ await on_intermediate_async(text)
493
+ await emitter.publish(
494
+ InvocationMessage(
495
+ origin=emitter.origin,
496
+ text=text,
497
+ is_final=False,
498
+ is_intermediate=True,
499
+ session_id=session_id,
500
+ )
501
+ )
502
+
503
+ client = await create_client(
504
+ active_profile,
505
+ on_intermediate_text_async=_publish_intermediate,
506
+ on_intermediate_text_sync=on_intermediate_sync,
507
+ session_id=session_id,
508
+ session_dir=effective_session_dir,
509
+ tool_result_ceiling_tokens=settings.tool_result_ceiling_tokens,
510
+ )
511
+ await prepared.own_or_release(client.aclose)
512
+
513
+ # Build tools from profile's builtin categories
514
+ from chrys.service.tools.builtins.web.build import assemble_web_tools
515
+ from chrys.service.tools.registry import ToolRegistry
516
+
517
+ await _progress(AGENT_LOAD_PHASE_TOOLS, "Loading built-in tools", status=AGENT_LOAD_STATUS_RUNNING)
518
+ tool_registry = ToolRegistry(vision_enabled=active_profile.vision)
519
+ builtin_categories = profile.tools.builtins or []
520
+ web_tools = assemble_web_tools(
521
+ builtin_categories,
522
+ settings,
523
+ profile.tools.web_search,
524
+ profile.tools.web_fetch,
525
+ chat_options=chat_options,
526
+ agent=profile.name,
527
+ model_profile_id=active_profile.id,
528
+ session_id=session_id,
529
+ )
530
+ tool_registry.load_builtins(
531
+ builtin_categories,
532
+ runtime=runtime,
533
+ settings=settings,
534
+ shell_filter_config=profile.tools.shell_filter,
535
+ session_id=session_id,
536
+ session_dir=effective_session_dir,
537
+ web=web_tools,
538
+ )
539
+ # Published once the web tools are decided, like the skill and memory warnings
540
+ # further on; a later step can still fail the whole build.
541
+ for warning in web_tools.warnings:
542
+ await bus.publish(warning)
543
+ from chrys.service.vision import filter_image_tools
544
+
545
+ tools = filter_image_tools(tool_registry.get_all(), vision_enabled=active_profile.vision)
546
+ if not allow_user_interaction:
547
+ tools = [tool for tool in tools if get_tool_kind(tool) != KIND_ASK_USER]
548
+ builtin_tools: dict[str, list[str]] = {}
549
+ for category in dict.fromkeys(builtin_categories):
550
+ names = [
551
+ tool.name
552
+ for tool in filter_image_tools(
553
+ tool_registry.get_by_category(category), vision_enabled=active_profile.vision
554
+ )
555
+ if allow_user_interaction or get_tool_kind(tool) != KIND_ASK_USER
556
+ ]
557
+ if names:
558
+ builtin_tools[category] = names
559
+ builtin_tool_count = len(tools)
560
+ await _progress(
561
+ AGENT_LOAD_PHASE_TOOLS,
562
+ "Built-in tools loaded",
563
+ current=builtin_tool_count,
564
+ total=builtin_tool_count,
565
+ status=AGENT_LOAD_STATUS_DONE,
566
+ )
567
+
568
+ # Collect workspace roots for file-write auto-approval (needed by both
569
+ # the main agent's ApprovalMiddleware and each sub-agent's fresh one).
570
+ workspace_roots: list[str] = []
571
+ if workspace:
572
+ workspace_roots.append(workspace.primary_cwd)
573
+ workspace_roots.extend(wd.path for wd in workspace.working_dirs)
574
+
575
+ # Build sub-agent tools at the composition root. The displaced owner
576
+ # stays live until construction atomically installs this result.
577
+ sub_agent_tools: SubAgentTools | None = None
578
+ sub_agent_tool_names: list[str] = []
579
+ from chrys.service.skills.adapter import create_skills_provider
580
+
581
+ if profile.sub_agents.agents and agent_registry:
582
+ sub_agent_total = len(profile.sub_agents.agents)
583
+ await _progress(
584
+ AGENT_LOAD_PHASE_SUB_AGENTS,
585
+ "Loading sub-agent tools",
586
+ current=0,
587
+ total=sub_agent_total,
588
+ status=AGENT_LOAD_STATUS_RUNNING,
589
+ )
590
+ from chrys.orchestration.sub_agents.tools import SubAgentTools
591
+
592
+ sub_agent_tools = SubAgentTools(
593
+ max_total_concurrency=profile.sub_agents.max_total_concurrency,
594
+ event_bus=bus,
595
+ session_id=session_id,
596
+ session_dir=effective_session_dir,
597
+ on_sub_agent_usage=on_sub_agent_usage,
598
+ on_side_call_usage=on_side_call_usage,
599
+ drain_parent_usage_publishes=drain_parent_usage_publishes,
600
+ parent_approval=profile.approval,
601
+ mutation_tracker=mutation_tracker,
602
+ mutation_coordinator=mutation_coordinator,
603
+ approval_mode=approval_mode,
604
+ approval_judge=approval_judge,
605
+ workspace_roots=workspace_roots,
606
+ approval_log_dir=approval_log_dir,
607
+ mcp_cache=mcp_cache,
608
+ hook_manager=hook_manager,
609
+ workspace_cwd=runtime.cwd,
610
+ serialize_implicit_windows=serialize_implicit_windows,
611
+ spill_quota=spill_quota,
612
+ ask_user_timeout_seconds=settings.ask_user_timeout_seconds,
613
+ turn_context=turn_context,
614
+ max_transient_retries=transient_retries,
615
+ tool_result_ceiling_tokens=settings.tool_result_ceiling_tokens,
616
+ allow_user_interaction=allow_user_interaction,
617
+ # A headless run shows no card to pause on, so a failed child ends with its error.
618
+ human_failure_decisions=allow_user_interaction,
619
+ )
620
+ prepared.own(sub_agent_tools.cleanup)
621
+ for index, ref in enumerate(profile.sub_agents.agents, start=1):
622
+ await _progress(
623
+ AGENT_LOAD_PHASE_SUB_AGENTS,
624
+ f"Loading sub-agent {ref.profile}",
625
+ server_name=ref.profile,
626
+ current=index - 1,
627
+ total=sub_agent_total,
628
+ status=AGENT_LOAD_STATUS_RUNNING,
629
+ subject=ref.profile,
630
+ )
631
+ sub_profile = agent_registry.get(ref.profile)
632
+ if sub_profile is None:
633
+ logger.warning("Sub-agent profile not found: %s", ref.profile)
634
+ await _progress(
635
+ AGENT_LOAD_PHASE_SUB_AGENTS,
636
+ f"Skipped sub-agent {ref.profile}",
637
+ server_name=ref.profile,
638
+ current=index,
639
+ total=sub_agent_total,
640
+ status=AGENT_LOAD_STATUS_SKIPPED,
641
+ subject=ref.profile,
642
+ )
643
+ continue
644
+ registration_state = effective_sub_agents[index - 1]["state"]
645
+ if registration_state in {"empty_command", "depth_limit"}:
646
+ reason = sub_agent_skip_reason(registration_state, acp_depth=acp_depth)
647
+ logger.warning("Skipping sub-agent profile %s: %s", ref.profile, reason)
648
+ await _progress(
649
+ AGENT_LOAD_PHASE_SUB_AGENTS,
650
+ f"Skipped sub-agent {ref.profile}: {reason}",
651
+ server_name=ref.profile,
652
+ current=index,
653
+ total=sub_agent_total,
654
+ status=AGENT_LOAD_STATUS_SKIPPED,
655
+ subject=ref.profile,
656
+ detail=reason,
657
+ )
658
+ continue
659
+ if sub_profile.acp is not None:
660
+ await sub_agent_tools.register_acp(ref, sub_profile, runtime)
661
+ else:
662
+ await sub_agent_tools.register(
663
+ ref,
664
+ sub_profile,
665
+ runtime,
666
+ settings=settings,
667
+ fallback_profile=active_profile,
668
+ model_registry=model_registry,
669
+ )
670
+ await _progress(
671
+ AGENT_LOAD_PHASE_SUB_AGENTS,
672
+ f"Loaded sub-agent {ref.profile}",
673
+ server_name=ref.profile,
674
+ current=index,
675
+ total=sub_agent_total,
676
+ status=AGENT_LOAD_STATUS_DONE,
677
+ subject=ref.profile,
678
+ )
679
+ sub_agent_tool_instances = sub_agent_tools.get_tools()
680
+ sub_agent_tool_names = [tool.name for tool in sub_agent_tool_instances]
681
+ tools.extend(sub_agent_tool_instances)
682
+
683
+ # Build MCP tools; the new Prepared owns this acquisition.
684
+ mcp_adapter: MCPAdapter | None = None
685
+ mcp_tools_by_server: dict[str, list[str]] = {}
686
+ if profile.tools.mcp:
687
+ from chrys.service.mcp.adapter import MCPAdapter
688
+ from chrys.service.mcp.thinking_warning import warn_if_tool_loading_unbinds_thinking
689
+
690
+ reserved_tool_names = chrys_reserved_tool_names()
691
+ reserved_tool_names.update(tool.name for tool in tools)
692
+ # A provider-hosted web tool owns its name too, so a clashing MCP tool fails
693
+ # the build with the guidance to rename or exclude it.
694
+ reserved_tool_names.update(web_tools.hosted)
695
+ mcp_adapter = MCPAdapter(
696
+ bus=bus,
697
+ session_id=session_id,
698
+ cache=mcp_cache,
699
+ stdio_cwd=runtime.cwd,
700
+ session_dir=effective_session_dir,
701
+ reserved_tool_names=reserved_tool_names,
702
+ )
703
+ prepared.own(mcp_adapter.disconnect_all)
704
+ enabled_mcp = [config for config in profile.tools.mcp if config.enabled]
705
+ if enabled_mcp:
706
+ await _progress(
707
+ AGENT_LOAD_PHASE_MCP,
708
+ "Connecting MCP servers",
709
+ total=len(enabled_mcp),
710
+ status=AGENT_LOAD_STATUS_RUNNING,
711
+ )
712
+
713
+ async def _mcp_progress(config: Any, state: str, current: int, total: int, failed: int) -> None:
714
+ action = {
715
+ "starting": "Connecting",
716
+ "connected": "Connected",
717
+ "failed": "Failed",
718
+ }.get(state, "Loading")
719
+ status = {
720
+ "starting": AGENT_LOAD_STATUS_RUNNING,
721
+ "connected": AGENT_LOAD_STATUS_DONE,
722
+ "failed": AGENT_LOAD_STATUS_FAILED,
723
+ }.get(state, AGENT_LOAD_STATUS_RUNNING)
724
+ await _progress(
725
+ AGENT_LOAD_PHASE_MCP,
726
+ f"{action} MCP server {config.name}",
727
+ server_name=config.name,
728
+ current=current,
729
+ total=total,
730
+ failed=failed,
731
+ status=status,
732
+ subject=config.name,
733
+ )
734
+
735
+ mcp_tools = await mcp_adapter.connect_all(profile.tools.mcp, progress=_mcp_progress)
736
+ mcp_tools_by_server = mcp_adapter.tool_names_by_server
737
+ tools.extend(mcp_tools)
738
+ warn_if_tool_loading_unbinds_thinking(profile, active_profile, chat_options, mcp_tools_by_server)
739
+
740
+ # Build skills provider (if configured)
741
+ await _progress(AGENT_LOAD_PHASE_SKILLS, "Loading skills", status=AGENT_LOAD_STATUS_RUNNING)
742
+ context_providers = []
743
+ progressive_resume_provider = mcp_adapter.create_resume_provider() if mcp_adapter is not None else None
744
+
745
+ skills_provider, skill_warnings = await create_skills_provider(
746
+ profile.skills,
747
+ runtime=runtime,
748
+ session_dir=effective_session_dir,
749
+ project_skills_enabled=settings.project_skills_enabled,
750
+ )
751
+ if skills_provider is not None:
752
+ context_providers.append(skills_provider)
753
+ if progressive_resume_provider is not None:
754
+ # Run after history and skills so restored calls can be inspected
755
+ # and newly advertised always-load tools can detect every visible
756
+ # name before contributing to this invocation.
757
+ context_providers.append(progressive_resume_provider)
758
+ for warn in skill_warnings:
759
+ await bus.publish(Warning(code=warn.code, message=warn.message, session_id=session_id))
760
+ skill_names = skills_provider.skill_names() if skills_provider else []
761
+ skill_sources = skills_provider.skill_sources() if skills_provider else {}
762
+ skill_details = skills_provider.skill_details() if skills_provider else []
763
+ await _progress(
764
+ AGENT_LOAD_PHASE_SKILLS,
765
+ "Skills loaded",
766
+ current=len(skill_names),
767
+ total=len(skill_names),
768
+ status=AGENT_LOAD_STATUS_DONE,
769
+ )
770
+
771
+ if memory_content.truncated:
772
+ await bus.publish(memory_truncated_warning(memory_content, session_id=session_id))
773
+
774
+ # Capture tool/skill names
775
+ await _progress(AGENT_LOAD_PHASE_AGENT, "Finalizing agent", status=AGENT_LOAD_STATUS_RUNNING)
776
+ tool_names = [t.name for t in tools]
777
+ tool_kinds = {t.name: k for t in tools if (k := get_tool_kind(t))}
778
+ context_tool_names = ctx.context_mgmt_provider.tool_names if ctx.context_mgmt_provider is not None else []
779
+ skill_tool_names = skills_provider.tool_names if skills_provider is not None else []
780
+ mcp_failures = {name: str(err) for name, err in (mcp_adapter.failures if mcp_adapter else {}).items()}
781
+ runtime_details = AgentRuntimeDetails(
782
+ model=RuntimeModelDetails(
783
+ profile_id=active_profile.id,
784
+ name=active_profile.name,
785
+ provider=active_profile.provider,
786
+ api_style=_runtime_api_style(active_profile.provider, active_profile.api_style),
787
+ model_id=active_profile.model_id,
788
+ max_context_tokens=active_profile.max_context_tokens,
789
+ base_url=effective_model_base_url(active_profile),
790
+ stream=active_profile.stream,
791
+ vision=active_profile.vision,
792
+ selection_source=model_selection.source,
793
+ ),
794
+ builtin_tools=builtin_tools,
795
+ web_search_providers=web_tools.provider_origins(),
796
+ sub_agent_tools=sub_agent_tool_names,
797
+ mcp_tools=mcp_tools_by_server,
798
+ mcp_failures=mcp_failures,
799
+ skill_sources=skill_sources,
800
+ skill_details=skill_details,
801
+ hook_sources=_runtime_hook_sources(hook_manager),
802
+ memory_sources=memory_content.loaded_files_by_source,
803
+ )
804
+
805
+ # Loop-message recorder for interrupt recovery — fed per run by the
806
+ # chrys ToolLoopLayer via client_kwargs (TurnBindings._build_run_kwargs).
807
+ loop_recorder = LoopRecorder(
808
+ capture_service_loop_messages=capture_service_loop_messages,
809
+ message_hasher=serialized_message_payload,
810
+ )
811
+
812
+ # Todo wiring gates on the profile category; the tracker's own
813
+ # lifecycle (create/hydrate/save) is profile-independent and engine-owned.
814
+ todo_enabled = "todo" in builtin_categories and todo_tracker is not None
815
+
816
+ # System reminder middleware (ChatMiddleware) — enriches the user
817
+ # message with <system-reminder> tags before each LLM call.
818
+ # Placed last so it runs closest to the LLM.
819
+ reminder_inputs = ReminderInputs(
820
+ runtime=runtime,
821
+ max_context_tokens=active_profile.max_context_tokens,
822
+ warn_threshold_pct=settings.warn_threshold_pct,
823
+ sub_agent_names=[t.name for t in sub_agent_tools.get_tools()] if sub_agent_tools else None,
824
+ shell_tool_enabled=KIND_SHELL in tool_kinds.values(),
825
+ tool_names=[*tool_names, *context_tool_names, *skill_tool_names],
826
+ session_root=effective_session_dir,
827
+ file_read_available=KIND_FILESYSTEM_READ in tool_kinds.values(),
828
+ spill_quota=spill_quota,
829
+ skill_catalog_provider=skills_provider.render_catalog_reminder if skills_provider else None,
830
+ todo_state_provider=partial(_render_todo_reminder, todo_tracker) if todo_enabled else None,
831
+ mcp_instructions_provider=mcp_adapter.render_instructions_reminder if mcp_adapter is not None else None,
832
+ file_change_provider=file_change_provider,
833
+ )
834
+
835
+ # Wire up Phase 4 LAST_WORDS generator for the main agent. Sub-agents
836
+ # do the same wiring in ``SubAgentTools.register`` using their own
837
+ # profile.compaction and their own SystemReminderMiddleware. The
838
+ # log dir is derived from ``session_dir`` (computed above), so tests
839
+ # using ``tmp_path`` stores keep all log output in the temp dir.
840
+
841
+ async def _publish_last_words_retry(info: RetryAttemptInfo) -> None:
842
+ emitter = invocation_publishers.capture()
843
+ await emitter.publish(
844
+ InvocationRetryAttempt(
845
+ origin=emitter.origin,
846
+ message=f"LAST_WORDS compaction: {info.reason}",
847
+ attempt=info.attempt,
848
+ max_attempts=info.max_attempts,
849
+ delay_seconds=int(info.delay_seconds),
850
+ scope="compaction",
851
+ session_id=session_id,
852
+ display_message=_RETRY_LAST_WORDS_COMPACTION.bind(reason=DisplayBlock(info.reason)),
853
+ detail=info.reason,
854
+ )
855
+ )
856
+
857
+ async def _publish_compaction_status(status: CompactionStatus) -> None:
858
+ if status.stage == "started":
859
+ await bus.publish(CompactionStarted(compaction_id=status.compaction_id, session_id=session_id))
860
+ return
861
+ if status.stage == "committed":
862
+ # The main agent has a dedicated post-commit signal already
863
+ # (``on_compaction`` → ToolCompacted); mapping this to
864
+ # CompactionFinished would publish a bogus second finish.
865
+ return
866
+ await bus.publish(
867
+ CompactionFinished(
868
+ compaction_id=status.compaction_id,
869
+ outcome=status.outcome,
870
+ duration_ms=status.duration_ms,
871
+ last_words=status.last_words,
872
+ format_violation=status.format_violation,
873
+ failure_reason=status.failure_reason,
874
+ session_id=session_id,
875
+ )
876
+ )
877
+
878
+ last_words_inputs = LastWordsInputs(
879
+ profile=active_profile,
880
+ template=profile.compaction.last_words_template,
881
+ max_output_tokens=profile.compaction.last_words_max_output_tokens,
882
+ log_dir=last_words_log_dir,
883
+ session_id=last_words_session_id,
884
+ parent_session_id=session_id,
885
+ session_dir=effective_session_dir,
886
+ max_transient_retries=transient_retries,
887
+ publish_retry=_publish_last_words_retry,
888
+ publish_status=_publish_compaction_status,
889
+ report_usage=on_side_call_usage,
890
+ )
891
+
892
+ # Response-validation middleware — placed innermost (closest to
893
+ # ``_inner_get_response``) so its retries on structurally invalid
894
+ # responses do not double-fire outer middleware (usage, system
895
+ # reminder, loop capture). On exhausted retries the response is
896
+ # returned with ``function_call`` contents stripped (so the tool
897
+ # loop exits cleanly) and structurally-empty assistant messages
898
+ # dropped from both ``response.messages`` and ``updates`` (so the
899
+ # streaming rebuild + persistence stay clean). Empty-assistant
900
+ # scrub also runs on the valid path to catch ``[empty, valid]``
901
+ # multi-message shapes that pass validation but would otherwise
902
+ # land a stray ``content: []`` message in ``session.json``.
903
+ # ``publish_retry`` surfaces client-mode validation retries on the
904
+ # bus; service-side failures raise to the executor's whole-run
905
+ # retry, which publishes its own ``RetryAttempt``.
906
+ async def _publish_validation_retry(info: RetryAttemptInfo) -> None:
907
+ emitter = invocation_publishers.capture()
908
+ await emitter.publish(
909
+ InvocationRetryAttempt(
910
+ scope="wire",
911
+ origin=emitter.origin,
912
+ message=f"Invalid response: {info.reason}",
913
+ attempt=info.attempt,
914
+ max_attempts=info.max_attempts,
915
+ delay_seconds=int(info.delay_seconds),
916
+ session_id=session_id,
917
+ display_message=_RETRY_INVALID_RESPONSE.bind(reason=DisplayBlock(info.reason)),
918
+ detail=info.reason,
919
+ )
920
+ )
921
+
922
+ recipe = MainRecipe(
923
+ context=context_inputs,
924
+ reminder=reminder_inputs,
925
+ last_words=last_words_inputs,
926
+ injection=InjectionMiddleware,
927
+ validation=lambda owner: create_validation(owner, publish_retry=_publish_validation_retry),
928
+ persist_recovery=persist_recovery_now,
929
+ )
930
+ web_tools.check_names(tools)
931
+
932
+ assembled = create_runtime(
933
+ conversation,
934
+ SharedRuntime(
935
+ client=client,
936
+ name="Chrys",
937
+ instructions=profile.instructions,
938
+ tools=tools,
939
+ providers=context_providers,
940
+ vision=active_profile.vision,
941
+ ),
942
+ recipe,
943
+ context=ctx,
944
+ injection=injection,
945
+ )
946
+ validation_middleware = assembled.validation
947
+ if validation_middleware is None:
948
+ raise RuntimeError("The main agent assembly requires response validation middleware.")
949
+ agent = assembled.agent
950
+ reminder_middleware = assembled.reminder
951
+ last_words = assembled.last_words
952
+ await agent.__aenter__()
953
+ # Register agent cleanup BEFORE anything below can fail — an un-exited
954
+ # Agent leaks its transport/session.
955
+ await prepared.own_or_release(partial(agent.__aexit__, None, None, None))
956
+
957
+ # Create executor
958
+ session = agent.create_session()
959
+ approval_policy = ApprovalPolicy(profile.approval, tools=tools)
960
+
961
+ approval_middleware = await create_approval(
962
+ conversation,
963
+ ApprovalInputs(
964
+ reuse=ApprovalReuseBinding(runtime, tools, session_id=session_id)
965
+ if session_id or runtime.session_id
966
+ else None,
967
+ approval_policy=approval_policy,
968
+ event_bus=bus,
969
+ session_id=session_id,
970
+ tool_kinds=tool_kinds,
971
+ caller_name=profile.display_name or profile.name,
972
+ workspace_roots=workspace_roots,
973
+ approval_mode=approval_mode,
974
+ approval_judge=approval_judge,
975
+ approval_log_dir=approval_log_dir,
976
+ workspace_cwd=runtime.cwd,
977
+ dev_mode=settings.dev_mode,
978
+ hook_manager=hook_manager,
979
+ profile_name=profile.name,
980
+ session_archive_read_roots=(
981
+ [effective_session_dir / COMPACTIONS_DIR_NAME] if effective_session_dir else None
982
+ ),
983
+ turn_context=turn_context,
984
+ ),
985
+ )
986
+ ask_user_middleware = create_ask_user(
987
+ conversation,
988
+ AskUserInputs(
989
+ event_bus=bus,
990
+ session_id=session_id,
991
+ caller_name=profile.display_name or profile.name,
992
+ timeout_seconds=settings.ask_user_timeout_seconds,
993
+ ),
994
+ )
995
+ extra_function_middleware: list[Any] = []
996
+ if todo_enabled and todo_tracker is not None:
997
+ extra_function_middleware.append(TodoMiddleware(bus, todo_tracker, session_id))
998
+ executor = TurnBindings(
999
+ conversation=conversation,
1000
+ agent=agent,
1001
+ session=session,
1002
+ event_bus=bus,
1003
+ approval_middleware=approval_middleware,
1004
+ ask_user_middleware=ask_user_middleware,
1005
+ injection_middleware=injection,
1006
+ loop_recorder=loop_recorder,
1007
+ session_id=session_id,
1008
+ compaction_strategy=ctx.compaction_strategy,
1009
+ stream=active_profile.stream,
1010
+ intermediate_buffer=intermediate_buffer,
1011
+ chat_options=chat_options,
1012
+ mutation_tracker=mutation_tracker,
1013
+ mutation_coordinator=mutation_coordinator,
1014
+ stream_attempt_timeout=active_profile.http_read_timeout,
1015
+ max_transient_retries=transient_retries,
1016
+ hook_manager=hook_manager,
1017
+ profile_name=profile.name,
1018
+ workspace_cwd=runtime.cwd,
1019
+ serialize_implicit_windows=serialize_implicit_windows,
1020
+ extra_function_middleware=extra_function_middleware,
1021
+ run_cycle_start_hooks=(
1022
+ web_tools.begin_pass,
1023
+ validation_middleware.reset_service_retry_state,
1024
+ ),
1025
+ hosted_commits_probe=validation_middleware.hosted_commits_observed,
1026
+ hosted_commits_in_flight_probe=validation_middleware.hosted_commits_in_flight,
1027
+ response_validation_middleware=validation_middleware,
1028
+ publish_intermediate_text=_publish_intermediate,
1029
+ invocation_publishers=invocation_publishers,
1030
+ commit_intermediate_text=commit_intermediate_text,
1031
+ tool_result_ceiling_tokens=settings.tool_result_ceiling_tokens,
1032
+ )
1033
+
1034
+ return AgentBuildResult(
1035
+ prepared=prepared,
1036
+ conversation=conversation,
1037
+ agent=agent,
1038
+ bindings=executor,
1039
+ runtime=runtime,
1040
+ loop_recorder=loop_recorder,
1041
+ reminder_middleware=reminder_middleware,
1042
+ last_words=last_words,
1043
+ sub_agent_tools=sub_agent_tools,
1044
+ mcp_adapter=mcp_adapter,
1045
+ skills_provider=skills_provider,
1046
+ tool_names=tool_names,
1047
+ tool_kinds=tool_kinds,
1048
+ skill_names=skill_names,
1049
+ memory_files=memory_content.loaded_files,
1050
+ agent_profile_fingerprint=agent_profile_fingerprint,
1051
+ model_profile_fingerprint=model_profile_fingerprint,
1052
+ runtime_details=runtime_details,
1053
+ compaction_strategy=ctx.compaction_strategy,
1054
+ active_profile=active_profile,
1055
+ )
1056
+
1057
+ try:
1058
+ return await prepared.open(_acquire)
1059
+ except BaseException:
1060
+ await rollback_resources(prepared)
1061
+ raise