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,847 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+ # Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
3
+ # Contains code adapted from Microsoft Agent Framework (MIT License; see NOTICE).
4
+
5
+ """Stream events read back as chat response updates.
6
+
7
+ One :class:`StreamState` reads one stream. Events about an output item name
8
+ it by its output index, so the state keeps one :class:`OutputSlot` per index:
9
+ the function call it assembles, the hosted call and result contents later
10
+ events update in place, and the text contents its message envelope belongs
11
+ to. An update carries what the event added; a hosted content already sent
12
+ is sent again whenever an event changes it.
13
+
14
+ A function call is sent once, whole, when its item is done. What comes
15
+ after a call not yet done, in output order, waits for it, so the contents
16
+ keep the order of the output; hosted work that waits is reported at once as
17
+ :class:`~chrys.foundation.hosted_tools.HeldHostedEvidence`. The terminal
18
+ event sends whatever still waits.
19
+
20
+ A stream that announced a response must end with its terminal event: a
21
+ failure (``response.failed``, an ``error`` event, a failed or cancelled
22
+ terminal response) raises, and so does a stream that ends before it
23
+ (:meth:`StreamState.finish`). A response that refused or was filtered yet
24
+ asks for function calls raises too, whenever the refusal came, a refusal
25
+ only a message snapshot shows included: the response lands only after the
26
+ stream ends, so its calls never run. One without calls whose refusal no text
27
+ showed ends as filtered (``content_filter``): it is refused, not blank. The
28
+ client reads nothing after the terminal event (:attr:`StreamState.ended`). A
29
+ stream that goes quiet before it is left to the stall watchdog, which sends
30
+ it again: unlike after a Chat Completions finish reason, nothing it said yet
31
+ tells how it ends.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import logging
37
+ from collections.abc import Callable, Mapping
38
+ from dataclasses import dataclass, field
39
+ from typing import TYPE_CHECKING, Any, Literal
40
+
41
+ from chrys.foundation.errors import ProviderResponseError, in_band_failure_retryable
42
+ from chrys.foundation.hosted_tools import (
43
+ PRESENTATION_TEXT_SEGMENT_ID_KEY,
44
+ HeldHostedEvidence,
45
+ HostedRetrySafety,
46
+ HostedToolPhase,
47
+ )
48
+ from chrys.kernel import (
49
+ OPENAI_OUTPUT_MESSAGE_ENVELOPE_KEY,
50
+ Annotation,
51
+ ChatResponseUpdate,
52
+ Content,
53
+ TextSpanRegion,
54
+ )
55
+ from chrys.kernel.exchanges import TOOL_RESULT_CONTENT_TYPES
56
+ from chrys.service.llm.chat_completions.decode import refused_calls_error
57
+ from chrys.service.profiles.models.options import effective_store_option
58
+
59
+ from .decode import (
60
+ RUNNING_STATUSES,
61
+ OpenAIContinuationToken,
62
+ continuation_token,
63
+ conversation_handle,
64
+ decode_client_tool_call,
65
+ decode_reasoning_item,
66
+ decode_usage,
67
+ finish_reason,
68
+ hosted_contents,
69
+ is_function_call,
70
+ logprobs_metadata,
71
+ output_message_envelope,
72
+ refuses,
73
+ response_failure,
74
+ timestamp,
75
+ )
76
+ from .hosted import decode_hosted_item, image_data_uri, item_properties, refresh_in_place
77
+
78
+ if TYPE_CHECKING:
79
+ from chrys.foundation.reasoning_origin import ReasoningOrigin
80
+ from chrys.kernel import UsageDetails
81
+
82
+ from .client import ResponsesVariant
83
+
84
+ logger = logging.getLogger(__name__)
85
+
86
+ # Progress events of hosted tools; the last segment is the new status.
87
+ _STATUS_EVENTS = (
88
+ "response.web_search_call.in_progress",
89
+ "response.web_search_call.searching",
90
+ "response.web_search_call.completed",
91
+ "response.file_search_call.in_progress",
92
+ "response.file_search_call.searching",
93
+ "response.file_search_call.completed",
94
+ "response.mcp_call.in_progress",
95
+ "response.mcp_call.completed",
96
+ "response.mcp_call.failed",
97
+ "response.code_interpreter_call.in_progress",
98
+ "response.code_interpreter_call.interpreting",
99
+ "response.code_interpreter_call.completed",
100
+ "response.image_generation_call.in_progress",
101
+ "response.image_generation_call.generating",
102
+ "response.image_generation_call.completed",
103
+ )
104
+
105
+
106
+ @dataclass(slots=True)
107
+ class PendingCall:
108
+ """A function call assembled from its events, held until its item is done."""
109
+
110
+ item_id: str | None = None
111
+ call_id: str | None = None
112
+ name: str | None = None
113
+ status: str | None = None
114
+ # The arguments the added item came with, the deltas after it, and the
115
+ # whole arguments a done event repeats, which win over the pieces.
116
+ initial: str = ""
117
+ deltas: list[str] = field(default_factory=list)
118
+ final: str | None = None
119
+ done: bool = False
120
+ sent: bool = False
121
+ raw: Any = None
122
+
123
+ def learn(self, item: Any) -> None:
124
+ """Take what an added or done item says about the call."""
125
+ self.item_id = getattr(item, "id", None) or self.item_id
126
+ self.call_id = getattr(item, "call_id", None) or self.call_id
127
+ self.name = getattr(item, "name", None) or self.name
128
+ self.status = getattr(item, "status", None) or self.status
129
+ self.raw = item
130
+
131
+ def content(self, output_index: Any) -> Content:
132
+ arguments = self.final or ("".join(self.deltas) if self.deltas else self.initial)
133
+ properties: dict[str, Any] = {"output_index": output_index, "fc_id": self.item_id}
134
+ if self.status:
135
+ properties["status"] = self.status
136
+ return Content.from_function_call(
137
+ call_id=self.call_id or "",
138
+ name=self.name or "",
139
+ arguments=arguments,
140
+ additional_properties=properties,
141
+ raw_representation=self.raw,
142
+ )
143
+
144
+
145
+ @dataclass(slots=True)
146
+ class OutputSlot:
147
+ """What the stream has seen of one output item."""
148
+
149
+ function_call: PendingCall | None = None
150
+ call: Content | None = None
151
+ result: Content | None = None
152
+ envelope: dict[str, str] | None = None
153
+ message_contents: list[Content] = field(default_factory=list)
154
+
155
+ def merge(self, snapshot: Content) -> Content:
156
+ """Fold a whole-item snapshot into the content already sent for its side.
157
+
158
+ The first snapshot becomes the carrier; later ones refresh it in
159
+ place, so everything holding the carrier sees the newest state.
160
+ """
161
+ if snapshot.type in TOOL_RESULT_CONTENT_TYPES:
162
+ self.result = _fold(self.result, snapshot)
163
+ return self.result
164
+ self.call = _fold(self.call, snapshot)
165
+ return self.call
166
+
167
+
168
+ def _fold(carrier: Content | None, snapshot: Content) -> Content:
169
+ if carrier is None:
170
+ return snapshot
171
+ refresh_in_place(carrier, snapshot)
172
+ return carrier
173
+
174
+
175
+ @dataclass(slots=True)
176
+ class _Update:
177
+ model: str
178
+ contents: list[Content] = field(default_factory=list)
179
+ metadata: dict[str, Any] = field(default_factory=dict)
180
+ conversation_id: str | None = None
181
+ response_id: str | None = None
182
+ created_at: str | None = None
183
+ continuation_token: OpenAIContinuationToken | None = None
184
+ finish_reason: Literal["length", "content_filter"] | None = None
185
+
186
+
187
+ class StreamState:
188
+ """Reads the events of one stream, in order."""
189
+
190
+ def __init__(
191
+ self,
192
+ options: Mapping[str, Any],
193
+ *,
194
+ model: str,
195
+ variant: ResponsesVariant,
196
+ origin: ReasoningOrigin | None = None,
197
+ ) -> None:
198
+ self._options = options
199
+ self._model = model
200
+ self._variant = variant
201
+ # The endpoint that sends the stream, stamped on its reasoning.
202
+ self._origin = origin
203
+ self._slots: dict[Any, OutputSlot] = {}
204
+ # Contents waiting behind a function call not yet done, by output
205
+ # index, and the hosted ones among them not yet reported.
206
+ self._held: dict[Any, list[Content]] = {}
207
+ self._held_hosted: list[Content] = []
208
+ # Reasoning items whose text came as deltas: their done event repeats it.
209
+ self._reasoning_with_deltas: set[str] = set()
210
+ # A lifecycle event announced the response; its terminal event came.
211
+ self._announced = False
212
+ self._ended = False
213
+ # A non-empty refusal came; a function call came; message text that
214
+ # is not blank went out.
215
+ self._refused = False
216
+ self._calls_seen = False
217
+ self._text_sent = False
218
+ # Local history replays reasoning by its encrypted payload, which may
219
+ # only arrive once the item or the whole response is done: it then
220
+ # goes onto the contents already sent for that item, by item id.
221
+ self._backfills_reasoning = variant.encrypted_reasoning and effective_store_option(options) is False
222
+ self._reasoning: dict[str, list[Content]] = {}
223
+
224
+ @property
225
+ def ended(self) -> bool:
226
+ """Whether the terminal event came: the response ended."""
227
+ return self._ended
228
+
229
+ def updates_for(self, event: Any) -> list[ChatResponseUpdate]:
230
+ """The updates one event makes: its own, after the evidence of hosted work it held."""
231
+ update = self.update_for(event)
232
+ if not self._held_hosted:
233
+ return [update]
234
+ evidence = ChatResponseUpdate(
235
+ contents=[],
236
+ role="assistant",
237
+ model=self._model,
238
+ raw_representation=HeldHostedEvidence(tuple(self._held_hosted)),
239
+ )
240
+ self._held_hosted.clear()
241
+ return [evidence, update]
242
+
243
+ def update_for(self, event: Any) -> ChatResponseUpdate:
244
+ """The update one event makes; what it adds behind a call not yet done waits for that call."""
245
+ update = _Update(model=self._model)
246
+ handler = _HANDLERS.get(event.type)
247
+ if handler is None:
248
+ logger.debug("Unparsed event of type: %s: %s", event.type, event)
249
+ else:
250
+ handler(self, event, update)
251
+ index = getattr(event, "output_index", None)
252
+ if update.contents and _output_order(index)[0] == 0 and self._waits_behind_call(index):
253
+ # A hosted content an event refreshes in place waits, and is
254
+ # reported, once.
255
+ held = self._held.setdefault(index, [])
256
+ fresh = [content for content in update.contents if all(content is not other for other in held)]
257
+ held.extend(fresh)
258
+ self._held_hosted.extend(content for content in fresh if content.provider_hosted)
259
+ update.contents = []
260
+ self._release(update, drain=False)
261
+ return ChatResponseUpdate(
262
+ contents=update.contents,
263
+ conversation_id=update.conversation_id,
264
+ response_id=update.response_id,
265
+ role="assistant",
266
+ model=update.model,
267
+ created_at=update.created_at,
268
+ continuation_token=update.continuation_token,
269
+ finish_reason=update.finish_reason,
270
+ additional_properties=update.metadata,
271
+ raw_representation=event,
272
+ )
273
+
274
+ def finish(self) -> ChatResponseUpdate | None:
275
+ """What the stream still owes when it ends.
276
+
277
+ A stream that announced its response but ended before the terminal
278
+ event lost the rest of it: that is a truncation the next attempt
279
+ may resume. A stream with no lifecycle events at all (some
280
+ compatible endpoints send none) is kept, with a warning, and the
281
+ calls it still holds are sent. A stream that refused yet asks for
282
+ calls fails as filtered either way.
283
+ """
284
+ if self._ended:
285
+ return None
286
+ self._refuse_calls()
287
+ if self._announced:
288
+ raise ProviderResponseError(
289
+ "stream_truncated", "The stream ended before the response finished.", retryable=True
290
+ )
291
+ logger.warning("Responses stream ended without a terminal event; the answer may be incomplete")
292
+ update = _Update(model=self._model)
293
+ self._release(update, drain=True)
294
+ reason = self._finish_reason(None)
295
+ if not update.contents and reason is None:
296
+ return None
297
+ return ChatResponseUpdate(contents=update.contents, role="assistant", model=update.model, finish_reason=reason)
298
+
299
+ def _finish_reason(
300
+ self, reason: Literal["length", "content_filter"] | None
301
+ ) -> Literal["length", "content_filter"] | None:
302
+ """*reason*, or ``content_filter`` for a refusal no text showed (a message snapshot's only).
303
+
304
+ The response is not blank for want of an answer: it was refused, and
305
+ sending it again meets the same refusal.
306
+ """
307
+ return "content_filter" if self._refused and not self._text_sent else reason
308
+
309
+ def _slot(self, index: Any) -> OutputSlot:
310
+ return self._slots.setdefault(index, OutputSlot())
311
+
312
+ def _pending_call(self, index: Any) -> PendingCall:
313
+ slot = self._slot(index)
314
+ if slot.function_call is None:
315
+ slot.function_call = PendingCall()
316
+ self._calls_seen = True
317
+ return slot.function_call
318
+
319
+ def _waits_behind_call(self, index: Any) -> bool:
320
+ """Whether a function call before *index* in output order is not sent yet."""
321
+ return any(
322
+ slot.function_call is not None
323
+ and not slot.function_call.sent
324
+ and _output_order(other) < _output_order(index)
325
+ for other, slot in self._slots.items()
326
+ )
327
+
328
+ def _release(self, update: _Update, *, drain: bool) -> None:
329
+ """Send what waits, in output order, up to the first call not done; with *drain*, all of it.
330
+
331
+ A call waits for every call before it, so a later call that is done
332
+ first does not overtake it, and neither does what follows either.
333
+ """
334
+ unsent = {index for index, slot in self._slots.items() if slot.function_call and not slot.function_call.sent}
335
+ for index in sorted(unsent | self._held.keys(), key=_output_order):
336
+ slot = self._slots.get(index)
337
+ call = slot.function_call if slot is not None else None
338
+ if call is not None and not call.sent:
339
+ if not (drain or call.done):
340
+ return
341
+ call.sent = True
342
+ if call.call_id and call.name:
343
+ update.contents.append(call.content(index))
344
+ else:
345
+ logger.warning("Responses stream dropped a function call without a call id or name at %r", index)
346
+ update.contents.extend(self._held.pop(index, ()))
347
+
348
+ def _unsent_hosted(self, response: Any) -> list[Content]:
349
+ """The hosted work in a terminal response's output that the stream never sent, or still holds."""
350
+ output = getattr(response, "output", None) or []
351
+ unsent = [
352
+ item
353
+ for index, item in enumerate(output)
354
+ if (slot := self._slots.get(index)) is None
355
+ or (slot.call is None and slot.result is None)
356
+ or index in self._held
357
+ ]
358
+ return hosted_contents(unsent, self._variant.hosted_provider)
359
+
360
+ def _remember_reasoning(self, contents: list[Content]) -> None:
361
+ """Stamp new reasoning contents with the endpoint, and keep them for a later payload."""
362
+ for content in contents:
363
+ if self._origin is not None:
364
+ self._origin.stamp(content.additional_properties)
365
+ if self._backfills_reasoning and content.id:
366
+ self._reasoning.setdefault(content.id, []).append(content)
367
+
368
+ def _backfill_reasoning(self, item: Any, *, final: bool) -> bool:
369
+ """Put a reasoning item's payload on the last content sent for it; False when none was.
370
+
371
+ A done item's payload is *final*; the terminal response's only fills
372
+ a gap, never replacing a payload the contents already carry.
373
+ """
374
+ payload = getattr(item, "encrypted_content", None)
375
+ item_id = getattr(item, "id", None)
376
+ sent = self._reasoning.get(item_id) if isinstance(item_id, str) else None
377
+ if not (payload and sent):
378
+ return False
379
+ if final or not any(content.protected_data for content in sent):
380
+ sent[-1].protected_data = payload
381
+ return True
382
+
383
+ def _store(self) -> Any:
384
+ return effective_store_option(self._options)
385
+
386
+ # Text
387
+
388
+ def _part_added(self, event: Any, update: _Update) -> None:
389
+ part = event.part
390
+ if part.type == "output_text":
391
+ update.contents.append(self._message_text(event, part.text))
392
+ update.metadata.update(logprobs_metadata(part))
393
+ elif part.type == "refusal":
394
+ self._refused = self._refused or bool(part.refusal)
395
+ update.contents.append(self._message_text(event, part.refusal))
396
+
397
+ def _text_delta(self, event: Any, update: _Update) -> None:
398
+ update.contents.append(self._message_text(event, event.delta))
399
+ update.metadata.update(logprobs_metadata(event))
400
+
401
+ def _refusal_delta(self, event: Any, update: _Update) -> None:
402
+ self._refused = self._refused or bool(event.delta)
403
+ self._text_delta(event, update)
404
+
405
+ def _refusal_done(self, event: Any, update: _Update) -> None:
406
+ # Its text came as deltas.
407
+ self._refused = self._refused or bool(getattr(event, "refusal", None))
408
+
409
+ def _part_done(self, event: Any, update: _Update) -> None:
410
+ # Its text came with the part or as deltas; a refusal may show only here.
411
+ part = event.part
412
+ if getattr(part, "type", None) == "refusal":
413
+ self._refused = self._refused or bool(getattr(part, "refusal", None))
414
+
415
+ def _annotation_added(self, event: Any, update: _Update) -> None:
416
+ if (citation := streamed_citation(event)) is not None:
417
+ update.contents.append(self._message_text(event, "", annotations=[citation]))
418
+
419
+ def _message_text(self, event: Any, text: str, annotations: list[Annotation] | None = None) -> Content:
420
+ """A text content of an output message, kept to receive its envelope when the item is done."""
421
+ properties: dict[str, Any] = {}
422
+ if segment_id := _text_segment_id(event):
423
+ properties[PRESENTATION_TEXT_SEGMENT_ID_KEY] = segment_id
424
+ index = getattr(event, "output_index", None)
425
+ tracked = isinstance(index, int) and not isinstance(index, bool)
426
+ if tracked and (envelope := self._slot(index).envelope):
427
+ properties[OPENAI_OUTPUT_MESSAGE_ENVELOPE_KEY] = dict(envelope)
428
+ content = Content.from_text(
429
+ text=text, annotations=annotations, raw_representation=event, additional_properties=properties or None
430
+ )
431
+ if tracked:
432
+ self._slot(index).message_contents.append(content)
433
+ self._text_sent = self._text_sent or bool(text.strip())
434
+ return content
435
+
436
+ # Reasoning
437
+
438
+ def _reasoning_delta(self, event: Any, update: _Update) -> None:
439
+ self._reasoning_with_deltas.add(event.item_id)
440
+ content = _reasoning_text(event, event.delta)
441
+ self._remember_reasoning([content])
442
+ update.contents.append(content)
443
+ update.metadata.update(logprobs_metadata(event))
444
+
445
+ def _reasoning_done(self, event: Any, update: _Update) -> None:
446
+ if event.item_id not in self._reasoning_with_deltas:
447
+ content = _reasoning_text(event, event.text)
448
+ self._remember_reasoning([content])
449
+ update.contents.append(content)
450
+ update.metadata.update(logprobs_metadata(event))
451
+
452
+ # Response lifecycle
453
+
454
+ def _started(self, event: Any, update: _Update) -> None:
455
+ """``response.created`` or ``response.in_progress``: only a running response can be resumed."""
456
+ self._announced = True
457
+ response = event.response
458
+ update.response_id = response.id
459
+ update.conversation_id = conversation_handle(response, store=self._store(), variant=self._variant)
460
+ if response.status in RUNNING_STATUSES:
461
+ update.continuation_token = continuation_token(response.id, store=self._store(), variant=self._variant)
462
+
463
+ def _finished(self, event: Any, update: _Update) -> None:
464
+ """``response.completed`` or ``response.incomplete``: the response ends here, unless it failed or refused."""
465
+ self._ended = True
466
+ response = event.response
467
+ usage = decode_usage(response.usage, variant=self._variant) if response.usage else None
468
+ self._refuse_calls(response, usage)
469
+ observed = self._unsent_hosted(response)
470
+ if (failure := response_failure(response, observed=observed, usage_details=usage)) is not None:
471
+ raise failure
472
+ reason = finish_reason(response)
473
+ output = getattr(response, "output", None) or []
474
+ if self._backfills_reasoning:
475
+ for item in output:
476
+ if getattr(item, "type", None) == "reasoning":
477
+ self._backfill_reasoning(item, final=False)
478
+ self._release(update, drain=True)
479
+ update.response_id = response.id
480
+ update.conversation_id = conversation_handle(response, store=self._store(), variant=self._variant)
481
+ update.model = response.model
482
+ update.created_at = timestamp(response.created_at)
483
+ if usage:
484
+ update.contents.append(Content.from_usage(usage_details=usage, raw_representation=event))
485
+ update.finish_reason = self._finish_reason(reason)
486
+
487
+ def _failed(self, event: Any, update: _Update) -> None:
488
+ """``response.failed``: the error it carries, the hosted work it ran included."""
489
+ self._ended = True
490
+ response = event.response
491
+ usage = decode_usage(response.usage, variant=self._variant) if response.usage else None
492
+ self._refuse_calls(response, usage)
493
+ observed = self._unsent_hosted(response)
494
+ raise response_failure(response, observed=observed, usage_details=usage) or ProviderResponseError(
495
+ "server_error",
496
+ "The service reported the response as failed.",
497
+ retryable=True,
498
+ invalidates_continuation_token=True,
499
+ observed_contents=tuple(observed),
500
+ usage_details=usage,
501
+ )
502
+
503
+ def _error(self, event: Any, update: _Update) -> None:
504
+ """An ``error`` event: the response ends with it."""
505
+ self._ended = True
506
+ self._refuse_calls()
507
+ code = getattr(event, "code", None) or "server_error"
508
+ raise ProviderResponseError(
509
+ code,
510
+ getattr(event, "message", None) or "The service reported an error.",
511
+ retryable=in_band_failure_retryable(code),
512
+ invalidates_continuation_token=True,
513
+ )
514
+
515
+ def failure(self) -> ProviderResponseError | None:
516
+ """The failure the events so far decide, however the stream goes on: a refusal with calls, or None.
517
+
518
+ The client asks here before reporting a stream that broke off.
519
+ """
520
+ return refused_calls_error() if self._refused and self._calls_seen else None
521
+
522
+ def _refuse_calls(self, response: Any = None, usage: UsageDetails | None = None) -> None:
523
+ """Fail a response that refused or was filtered yet asks for calls, however it ended.
524
+
525
+ *response* is the terminal response, when the stream sent one; a
526
+ call it lists counts even when no event streamed it.
527
+ """
528
+ if response is not None:
529
+ output = getattr(response, "output", None) or []
530
+ self._refused = self._refused or finish_reason(response) == "content_filter" or any(map(refuses, output))
531
+ self._calls_seen = self._calls_seen or any(map(is_function_call, output))
532
+ if self._refused and self._calls_seen:
533
+ raise refused_calls_error(self._unsent_hosted(response), usage_details=usage)
534
+
535
+ # Output items
536
+
537
+ def _item_added(self, event: Any, update: _Update) -> None:
538
+ item = event.item
539
+ index = getattr(event, "output_index", -1)
540
+ match item.type:
541
+ case "message":
542
+ # Its text comes as part events; a refusal may show only here.
543
+ self._refused = self._refused or refuses(item)
544
+ if envelope := output_message_envelope(item):
545
+ self._slot(index).envelope = envelope
546
+ case "function_call":
547
+ call = self._pending_call(index)
548
+ call.learn(item)
549
+ if isinstance(arguments := getattr(item, "arguments", None), str):
550
+ call.initial = arguments
551
+ case "reasoning":
552
+ contents = decode_reasoning_item(item, streamed=True)
553
+ self._remember_reasoning(contents)
554
+ update.contents.extend(contents)
555
+ case "shell_call_output" | "tool_search_output":
556
+ # Results are decoded once, from their done item.
557
+ pass
558
+ case _:
559
+ if decoded := decode_hosted_item(item, self._variant.hosted_provider, phase=HostedToolPhase.START):
560
+ self._slot(index).call = decoded[0]
561
+ update.contents.append(decoded[0])
562
+
563
+ def _item_done(self, event: Any, update: _Update) -> None:
564
+ item = event.item
565
+ index = getattr(event, "output_index", -1)
566
+ slot = self._slot(index)
567
+ match getattr(item, "type", None):
568
+ case "function_call":
569
+ call = self._pending_call(index)
570
+ call.learn(item)
571
+ if isinstance(arguments := getattr(item, "arguments", None), str) and arguments:
572
+ call.final = arguments
573
+ call.done = True
574
+ case "message":
575
+ self._refused = self._refused or refuses(item)
576
+ envelope = output_message_envelope(item)
577
+ if envelope:
578
+ slot.envelope = envelope
579
+ for content in slot.message_contents:
580
+ if envelope:
581
+ content.additional_properties[OPENAI_OUTPUT_MESSAGE_ENVELOPE_KEY] = dict(envelope)
582
+ else:
583
+ content.additional_properties.pop(OPENAI_OUTPUT_MESSAGE_ENVELOPE_KEY, None)
584
+ case "reasoning":
585
+ # The payload only arrives once the item is done.
586
+ payload = getattr(item, "encrypted_content", None)
587
+ if payload and not self._backfill_reasoning(item, final=True):
588
+ content = Content.from_text_reasoning(
589
+ id=getattr(item, "id", None), text="", protected_data=payload, raw_representation=item
590
+ )
591
+ self._remember_reasoning([content])
592
+ update.contents.append(content)
593
+ case "custom_tool_call":
594
+ name = getattr(item, "name", "") or ""
595
+ update.contents.append(decode_client_tool_call(item, name=name, arguments=getattr(item, "input", None)))
596
+ case "apply_patch_call":
597
+ operation = getattr(item, "operation", None)
598
+ update.contents.append(decode_client_tool_call(item, name="apply_patch", arguments=operation))
599
+ case item_type:
600
+ snapshots = decode_hosted_item(item, self._variant.hosted_provider) or []
601
+ update.contents.extend(slot.merge(snapshot) for snapshot in snapshots)
602
+ if item_type == "image_generation_call" and len(snapshots) == 1 and slot.result is not None:
603
+ # No final image: the result built from partial images ends here.
604
+ status = getattr(item, "status", None)
605
+ slot.result.status = status
606
+ slot.result.provider_status = status
607
+ slot.result.provider_phase = HostedToolPhase.TERMINAL
608
+ slot.result.additional_properties = item_properties(item, shadow=True)
609
+ slot.result.raw_representation = item
610
+ update.contents.append(slot.result)
611
+
612
+ # Tool progress
613
+
614
+ def _arguments_delta(self, event: Any, update: _Update) -> None:
615
+ # Held until the item is done; the update still shows progress.
616
+ call = self._pending_call(event.output_index)
617
+ call.item_id = call.item_id or event.item_id
618
+ call.deltas.append(event.delta)
619
+
620
+ def _arguments_done(self, event: Any, update: _Update) -> None:
621
+ call = self._pending_call(event.output_index)
622
+ call.item_id = call.item_id or event.item_id
623
+ if isinstance(arguments := getattr(event, "arguments", None), str) and arguments:
624
+ call.final = arguments
625
+
626
+ def _status_changed(self, event: Any, update: _Update) -> None:
627
+ call = self._slot(getattr(event, "output_index", -1)).call
628
+ if call is not None:
629
+ status = event.type.rsplit(".", 1)[-1]
630
+ call.status = status
631
+ call.provider_status = status
632
+ call.provider_phase = HostedToolPhase.SNAPSHOT
633
+ call.raw_representation = event
634
+ update.contents.append(call)
635
+
636
+ def _code_delta(self, event: Any, update: _Update) -> None:
637
+ properties = _code_properties(event)
638
+ slot = self._slot(event.output_index)
639
+ call = slot.call
640
+ if call is None:
641
+ call = slot.call = self._code_call(event)
642
+ update.contents.append(call)
643
+ if not call.inputs:
644
+ call.inputs = [Content.from_text(text="")]
645
+ code = call.inputs[0]
646
+ code.text = (code.text or "") + event.delta
647
+ code.raw_representation = event
648
+ code.additional_properties = properties
649
+ call.provider_phase = HostedToolPhase.DELTA
650
+ call.raw_representation = event
651
+ if call not in update.contents:
652
+ update.contents.append(call)
653
+ update.metadata.update(logprobs_metadata(event))
654
+
655
+ def _code_done(self, event: Any, update: _Update) -> None:
656
+ properties = _code_properties(event)
657
+ slot = self._slot(event.output_index)
658
+ call = slot.call
659
+ if call is None:
660
+ call = slot.call = self._code_call(event)
661
+ call.inputs = [Content.from_text(text=event.code, raw_representation=event, additional_properties=properties)]
662
+ call.provider_phase = HostedToolPhase.SNAPSHOT
663
+ call.raw_representation = event
664
+ update.contents.append(call)
665
+ update.metadata.update(logprobs_metadata(event))
666
+
667
+ def _code_call(self, event: Any) -> Content:
668
+ """The code call for code that arrives before its item."""
669
+ return Content.from_code_interpreter_tool_call(
670
+ call_id=getattr(event, "call_id", None) or getattr(event, "id", None) or event.item_id,
671
+ inputs=[],
672
+ hosted_provider=self._variant.hosted_provider,
673
+ provider_item_type="code_interpreter_call",
674
+ provider_item_id=event.item_id,
675
+ retry_safety=HostedRetrySafety.SANDBOXED,
676
+ )
677
+
678
+ def _partial_image(self, event: Any, update: _Update) -> None:
679
+ """A partial image, added to a result that stays open until the item is done."""
680
+ image = Content.from_uri(
681
+ uri=image_data_uri(event.partial_image_b64),
682
+ additional_properties={"partial_image_index": event.partial_image_index, "is_partial_image": True},
683
+ raw_representation=event,
684
+ )
685
+ image_id = getattr(event, "item_id", None)
686
+ slot = self._slot(getattr(event, "output_index", -1))
687
+ provider = self._variant.hosted_provider
688
+ if slot.call is None:
689
+ slot.call = Content.from_image_generation_tool_call(
690
+ image_id=image_id,
691
+ hosted_provider=provider,
692
+ provider_item_type="image_generation_call",
693
+ provider_item_id=image_id,
694
+ provider_phase=HostedToolPhase.START,
695
+ retry_safety=HostedRetrySafety.SANDBOXED,
696
+ raw_representation=event,
697
+ )
698
+ update.contents.append(slot.call)
699
+ if slot.result is None:
700
+ slot.result = Content.from_image_generation_tool_result(
701
+ image_id=image_id,
702
+ outputs=[],
703
+ hosted_provider=provider,
704
+ provider_item_type="image_generation_call",
705
+ provider_item_id=image_id,
706
+ provider_phase=HostedToolPhase.SNAPSHOT,
707
+ provider_status="generating",
708
+ retry_safety=HostedRetrySafety.SANDBOXED,
709
+ raw_representation=event,
710
+ )
711
+ result = slot.result
712
+ if not isinstance(result.outputs, list):
713
+ result.outputs = []
714
+ result.outputs.append(image)
715
+ result.provider_phase = HostedToolPhase.SNAPSHOT
716
+ result.provider_status = "generating"
717
+ result.raw_representation = event
718
+ update.contents.append(result)
719
+
720
+
721
+ def _output_order(index: Any) -> tuple[int, int]:
722
+ """Output indexes in order; a missing one after them."""
723
+ if isinstance(index, int) and not isinstance(index, bool) and index >= 0:
724
+ return (0, index)
725
+ return (1, 0)
726
+
727
+
728
+ def _text_segment_id(event: Any) -> str:
729
+ """Which streamed text part *event* belongs to, unique within the response."""
730
+ item_id = getattr(event, "item_id", None)
731
+ index = getattr(event, "output_index", None)
732
+ part = getattr(event, "content_index", None)
733
+ if isinstance(item_id, str) and item_id:
734
+ segment = f"item:{item_id}"
735
+ elif isinstance(index, int) and not isinstance(index, bool):
736
+ segment = f"output:{index}"
737
+ else:
738
+ return ""
739
+ if isinstance(part, int) and not isinstance(part, bool):
740
+ return f"{segment}:content:{part}"
741
+ return segment
742
+
743
+
744
+ def _reasoning_text(event: Any, text: str) -> Content:
745
+ properties = {"reasoning_text": True} if event.type.startswith("response.reasoning_text.") else None
746
+ return Content.from_text_reasoning(
747
+ id=event.item_id, text=text, raw_representation=event, additional_properties=properties
748
+ )
749
+
750
+
751
+ def _code_properties(event: Any) -> dict[str, Any]:
752
+ return {"output_index": event.output_index, "sequence_number": event.sequence_number, "item_id": event.item_id}
753
+
754
+
755
+ def streamed_citation(event: Any) -> Annotation | None:
756
+ """The citation an ``output_text.annotation.added`` event adds, if it names its source.
757
+
758
+ The annotation may be a mapping or an object. Blocking responses
759
+ describe citations in another shape (:func:`.decode._citation`).
760
+ """
761
+ annotation = event.annotation
762
+
763
+ def value(key: str) -> Any:
764
+ if isinstance(annotation, dict):
765
+ return annotation.get(key)
766
+ return getattr(annotation, key, None)
767
+
768
+ kind = value("type")
769
+ file_id = value("file_id")
770
+ if kind == "file_path":
771
+ if not file_id:
772
+ return None
773
+ return Annotation(
774
+ type="citation",
775
+ file_id=str(file_id),
776
+ additional_properties={"annotation_index": event.annotation_index, "index": value("index")},
777
+ raw_representation=annotation,
778
+ )
779
+ if kind == "file_citation":
780
+ if not file_id:
781
+ return None
782
+ return Annotation(
783
+ type="citation",
784
+ file_id=str(file_id),
785
+ url=value("filename"),
786
+ additional_properties={"annotation_index": event.annotation_index, "index": value("index")},
787
+ raw_representation=annotation,
788
+ )
789
+ if kind == "container_file_citation":
790
+ if not file_id:
791
+ return None
792
+ citation = Annotation(
793
+ type="citation",
794
+ file_id=str(file_id),
795
+ url=value("filename"),
796
+ additional_properties={"annotation_index": event.annotation_index, "container_id": value("container_id")},
797
+ raw_representation=annotation,
798
+ )
799
+ elif kind == "url_citation":
800
+ url = value("url")
801
+ if not url:
802
+ return None
803
+ properties: dict[str, Any] = {"annotation_index": event.annotation_index}
804
+ if (get_url := value("get_url")) is not None:
805
+ properties["get_url"] = get_url
806
+ citation = Annotation(
807
+ type="citation",
808
+ title=value("title") or "",
809
+ url=str(url),
810
+ additional_properties=properties,
811
+ raw_representation=annotation,
812
+ )
813
+ else:
814
+ logger.debug("Unparsed annotation type in streaming: %s", kind)
815
+ return None
816
+ start, end = value("start_index"), value("end_index")
817
+ if start is not None and end is not None:
818
+ citation["annotated_regions"] = [TextSpanRegion(type="text_span", start_index=start, end_index=end)]
819
+ return citation
820
+
821
+
822
+ _HANDLERS: dict[str, Callable[[StreamState, Any, _Update], None]] = {
823
+ "response.content_part.added": StreamState._part_added,
824
+ "response.content_part.done": StreamState._part_done,
825
+ "response.output_text.delta": StreamState._text_delta,
826
+ "response.refusal.delta": StreamState._refusal_delta,
827
+ "response.refusal.done": StreamState._refusal_done,
828
+ "response.output_text.annotation.added": StreamState._annotation_added,
829
+ "response.reasoning_text.delta": StreamState._reasoning_delta,
830
+ "response.reasoning_summary_text.delta": StreamState._reasoning_delta,
831
+ "response.reasoning_text.done": StreamState._reasoning_done,
832
+ "response.reasoning_summary_text.done": StreamState._reasoning_done,
833
+ "response.created": StreamState._started,
834
+ "response.in_progress": StreamState._started,
835
+ "response.completed": StreamState._finished,
836
+ "response.incomplete": StreamState._finished,
837
+ "response.failed": StreamState._failed,
838
+ "error": StreamState._error,
839
+ "response.output_item.added": StreamState._item_added,
840
+ "response.output_item.done": StreamState._item_done,
841
+ "response.function_call_arguments.delta": StreamState._arguments_delta,
842
+ "response.function_call_arguments.done": StreamState._arguments_done,
843
+ "response.code_interpreter_call_code.delta": StreamState._code_delta,
844
+ "response.code_interpreter_call_code.done": StreamState._code_done,
845
+ "response.image_generation_call.partial_image": StreamState._partial_image,
846
+ **dict.fromkeys(_STATUS_EVENTS, StreamState._status_changed),
847
+ }