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.
- chrys/__init__.py +16 -0
- chrys/app/__init__.py +3 -0
- chrys/app/acp/__init__.py +3 -0
- chrys/app/acp/bridge.py +664 -0
- chrys/app/acp/content.py +132 -0
- chrys/app/acp/doc/frontend-api.md +425 -0
- chrys/app/acp/history.py +585 -0
- chrys/app/acp/server.py +1796 -0
- chrys/app/acp/session_manager.py +1815 -0
- chrys/app/acp/tool_status.py +45 -0
- chrys/app/cli/__init__.py +3 -0
- chrys/app/cli/acp.py +178 -0
- chrys/app/cli/app.py +165 -0
- chrys/app/cli/approvals.py +101 -0
- chrys/app/cli/headless.py +223 -0
- chrys/app/cli/launch_cwd.py +42 -0
- chrys/app/cli/profiles.py +298 -0
- chrys/app/cli/progress.py +857 -0
- chrys/app/cli/run.py +425 -0
- chrys/app/cli/serve.py +1593 -0
- chrys/app/cli/tool_summary.py +225 -0
- chrys/app/cli/trajectory.py +201 -0
- chrys/app/cli/workflow.py +601 -0
- chrys/app/features/__init__.py +3 -0
- chrys/app/features/buddy/__init__.py +3 -0
- chrys/app/features/buddy/actions.py +68 -0
- chrys/app/features/buddy/animation.py +76 -0
- chrys/app/features/buddy/commands.py +196 -0
- chrys/app/features/buddy/docs/design.md +187 -0
- chrys/app/features/buddy/hatchery.py +80 -0
- chrys/app/features/buddy/lifecycle.py +41 -0
- chrys/app/features/buddy/model.py +265 -0
- chrys/app/features/buddy/pixel_renderer.py +113 -0
- chrys/app/features/buddy/pixel_sprites.py +279 -0
- chrys/app/features/buddy/portrait.py +76 -0
- chrys/app/features/buddy/progression.py +58 -0
- chrys/app/features/buddy/replies.py +191 -0
- chrys/app/features/buddy/sprites/alien.toml +70 -0
- chrys/app/features/buddy/sprites/axolotl.toml +71 -0
- chrys/app/features/buddy/sprites/bat.toml +69 -0
- chrys/app/features/buddy/sprites/bee.toml +69 -0
- chrys/app/features/buddy/sprites/cactus.toml +73 -0
- chrys/app/features/buddy/sprites/capybara.toml +70 -0
- chrys/app/features/buddy/sprites/cat.toml +69 -0
- chrys/app/features/buddy/sprites/crab.toml +70 -0
- chrys/app/features/buddy/sprites/dragon.toml +71 -0
- chrys/app/features/buddy/sprites/duck.toml +69 -0
- chrys/app/features/buddy/sprites/fox.toml +69 -0
- chrys/app/features/buddy/sprites/frog.toml +70 -0
- chrys/app/features/buddy/sprites/ghost.toml +70 -0
- chrys/app/features/buddy/sprites/goose.toml +69 -0
- chrys/app/features/buddy/sprites/jelly.toml +70 -0
- chrys/app/features/buddy/sprites/llama.toml +70 -0
- chrys/app/features/buddy/sprites/mushroom.toml +69 -0
- chrys/app/features/buddy/sprites/octopus.toml +70 -0
- chrys/app/features/buddy/sprites/owl.toml +70 -0
- chrys/app/features/buddy/sprites/panda.toml +71 -0
- chrys/app/features/buddy/sprites/penguin.toml +69 -0
- chrys/app/features/buddy/sprites/rabbit.toml +70 -0
- chrys/app/features/buddy/sprites/robot.toml +72 -0
- chrys/app/features/buddy/sprites/shark.toml +70 -0
- chrys/app/features/buddy/sprites/snail.toml +69 -0
- chrys/app/features/buddy/sprites/snake.toml +69 -0
- chrys/app/features/buddy/sprites/tabby.toml +69 -0
- chrys/app/features/buddy/sprites/turtle.toml +69 -0
- chrys/app/features/buddy/store.py +143 -0
- chrys/app/features/session_title/__init__.py +7 -0
- chrys/app/features/session_title/updater.py +582 -0
- chrys/app/installer.py +651 -0
- chrys/app/parsing.py +17 -0
- chrys/app/tui/__init__.py +3 -0
- chrys/app/tui/app.py +1287 -0
- chrys/app/tui/behaviors/__init__.py +3 -0
- chrys/app/tui/behaviors/click_outside_dismiss.py +90 -0
- chrys/app/tui/behaviors/insert_clipboard.py +73 -0
- chrys/app/tui/behaviors/right_click_copy.py +146 -0
- chrys/app/tui/binding_display.py +139 -0
- chrys/app/tui/buddy_messages.py +17 -0
- chrys/app/tui/buddy_reply.py +86 -0
- chrys/app/tui/chrys.tcss +549 -0
- chrys/app/tui/clipboard.py +109 -0
- chrys/app/tui/copy_messages.py +10 -0
- chrys/app/tui/i18n.py +230 -0
- chrys/app/tui/language.py +58 -0
- chrys/app/tui/notifications/__init__.py +12 -0
- chrys/app/tui/notifications/drivers.py +180 -0
- chrys/app/tui/notifications/service.py +126 -0
- chrys/app/tui/notifications/settings.py +141 -0
- chrys/app/tui/screens/__init__.py +3 -0
- chrys/app/tui/screens/agents/__init__.py +8 -0
- chrys/app/tui/screens/agents/agent_draft_store.py +937 -0
- chrys/app/tui/screens/agents/config.py +2142 -0
- chrys/app/tui/screens/agents/config.tcss +169 -0
- chrys/app/tui/screens/agents/panels/__init__.py +3 -0
- chrys/app/tui/screens/agents/panels/acp.py +1176 -0
- chrys/app/tui/screens/agents/panels/basic.py +497 -0
- chrys/app/tui/screens/agents/panels/compaction.py +231 -0
- chrys/app/tui/screens/agents/panels/config_card.py +218 -0
- chrys/app/tui/screens/agents/panels/instructions.py +91 -0
- chrys/app/tui/screens/agents/panels/markdown_report.py +76 -0
- chrys/app/tui/screens/agents/panels/mcp.py +2262 -0
- chrys/app/tui/screens/agents/panels/memory.py +684 -0
- chrys/app/tui/screens/agents/panels/path_entry.py +227 -0
- chrys/app/tui/screens/agents/panels/skills.py +806 -0
- chrys/app/tui/screens/agents/panels/subagents.py +652 -0
- chrys/app/tui/screens/agents/panels/tools.py +205 -0
- chrys/app/tui/screens/agents/picker.py +103 -0
- chrys/app/tui/screens/agents/skill_paths.py +38 -0
- chrys/app/tui/screens/agents/validation_messages.py +452 -0
- chrys/app/tui/screens/dialogs/__init__.py +35 -0
- chrys/app/tui/screens/dialogs/agent_load.py +834 -0
- chrys/app/tui/screens/dialogs/agent_load.tcss +78 -0
- chrys/app/tui/screens/dialogs/app_mode.py +55 -0
- chrys/app/tui/screens/dialogs/approval/__init__.py +15 -0
- chrys/app/tui/screens/dialogs/approval/approval.tcss +311 -0
- chrys/app/tui/screens/dialogs/approval/bodies/__init__.py +3 -0
- chrys/app/tui/screens/dialogs/approval/bodies/file_edit.py +210 -0
- chrys/app/tui/screens/dialogs/approval/bodies/sub_agent.py +82 -0
- chrys/app/tui/screens/dialogs/approval/body.py +110 -0
- chrys/app/tui/screens/dialogs/approval/dialog.py +565 -0
- chrys/app/tui/screens/dialogs/approval/mode.py +105 -0
- chrys/app/tui/screens/dialogs/ask_user.py +148 -0
- chrys/app/tui/screens/dialogs/ask_user.tcss +62 -0
- chrys/app/tui/screens/dialogs/base.py +84 -0
- chrys/app/tui/screens/dialogs/confirm.py +184 -0
- chrys/app/tui/screens/dialogs/confirm.tcss +46 -0
- chrys/app/tui/screens/dialogs/connection_test.py +183 -0
- chrys/app/tui/screens/dialogs/connection_test.tcss +92 -0
- chrys/app/tui/screens/dialogs/diagram.py +102 -0
- chrys/app/tui/screens/dialogs/diagram.tcss +24 -0
- chrys/app/tui/screens/dialogs/editor.py +378 -0
- chrys/app/tui/screens/dialogs/editor.tcss +132 -0
- chrys/app/tui/screens/dialogs/file_picker.py +582 -0
- chrys/app/tui/screens/dialogs/file_picker.tcss +78 -0
- chrys/app/tui/screens/dialogs/fork_session.py +219 -0
- chrys/app/tui/screens/dialogs/fork_session.tcss +75 -0
- chrys/app/tui/screens/dialogs/image_compression.py +102 -0
- chrys/app/tui/screens/dialogs/image_compression.tcss +28 -0
- chrys/app/tui/screens/dialogs/man_page.py +172 -0
- chrys/app/tui/screens/dialogs/man_page.tcss +39 -0
- chrys/app/tui/screens/dialogs/new_folder.py +277 -0
- chrys/app/tui/screens/dialogs/new_folder.tcss +51 -0
- chrys/app/tui/screens/dialogs/notice.tcss +14 -0
- chrys/app/tui/screens/dialogs/prompt_cache.py +144 -0
- chrys/app/tui/screens/dialogs/prompt_cache.tcss +38 -0
- chrys/app/tui/screens/dialogs/runtime_details.py +371 -0
- chrys/app/tui/screens/dialogs/runtime_details.tcss +49 -0
- chrys/app/tui/screens/dialogs/session_title.py +110 -0
- chrys/app/tui/screens/dialogs/session_title.tcss +43 -0
- chrys/app/tui/screens/dialogs/tool_view.py +207 -0
- chrys/app/tui/screens/dialogs/tool_view.tcss +43 -0
- chrys/app/tui/screens/dialogs/vision_unsupported.py +122 -0
- chrys/app/tui/screens/dialogs/vision_unsupported.tcss +35 -0
- chrys/app/tui/screens/dialogs/workflow_confirm.py +91 -0
- chrys/app/tui/screens/dialogs/workflow_confirm.tcss +17 -0
- chrys/app/tui/screens/dialogs/workflow_input.py +258 -0
- chrys/app/tui/screens/dialogs/workflow_input.tcss +73 -0
- chrys/app/tui/screens/dialogs/workflow_node.py +462 -0
- chrys/app/tui/screens/dialogs/workflow_node.tcss +41 -0
- chrys/app/tui/screens/dialogs/workflow_picker.py +46 -0
- chrys/app/tui/screens/dialogs/workflow_result.py +136 -0
- chrys/app/tui/screens/dialogs/workflow_result.tcss +14 -0
- chrys/app/tui/screens/diff/__init__.py +22 -0
- chrys/app/tui/screens/diff/rollback_modal.py +1381 -0
- chrys/app/tui/screens/diff/rollback_modal.tcss +248 -0
- chrys/app/tui/screens/diff/screen.py +1532 -0
- chrys/app/tui/screens/diff/screen.tcss +104 -0
- chrys/app/tui/screens/guides/__init__.py +7 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/agents.md +178 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/approval.md +117 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/chat-options.md +276 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/compaction.md +42 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/memory.md +48 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/models.md +158 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/settings.md +210 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/themes.md +61 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/tools.md +60 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/web-tools.md +286 -0
- chrys/app/tui/screens/guides/_docs/en/guides/daily-use/sessions.md +77 -0
- chrys/app/tui/screens/guides/_docs/en/guides/daily-use/workspaces.md +51 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/external-acp-agents.md +126 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/hooks.md +167 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/mcp.md +95 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/skills.md +175 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/icode-acp.md +61 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/icode-run.md +190 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/icode-serve.md +239 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/workflows.md +664 -0
- chrys/app/tui/screens/guides/_docs/en/reference/agent-profile.md +548 -0
- chrys/app/tui/screens/guides/_docs/en/reference/hooks.md +602 -0
- chrys/app/tui/screens/guides/_docs/en/reference/opentelemetry.md +177 -0
- chrys/app/tui/screens/guides/_docs/en/reference/settings.md +245 -0
- chrys/app/tui/screens/guides/_docs/en/reference/themes.md +149 -0
- chrys/app/tui/screens/guides/_docs/en/reference/tool-kinds-and-names.md +58 -0
- chrys/app/tui/screens/guides/_docs/en/reference/tui-slash-commands.md +76 -0
- chrys/app/tui/screens/guides/_docs/en/reference/workflows.md +1006 -0
- chrys/app/tui/screens/guides/_docs/en/start/getting-started.md +170 -0
- chrys/app/tui/screens/guides/_docs/en/start/what-is-icode.md +34 -0
- chrys/app/tui/screens/guides/_docs/index.yaml +100 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/agents.md +178 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/approval.md +117 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/chat-options.md +276 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/compaction.md +42 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/memory.md +48 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/models.md +158 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/settings.md +210 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/themes.md +61 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/tools.md +60 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/web-tools.md +286 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/daily-use/sessions.md +77 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/daily-use/workspaces.md +51 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/external-acp-agents.md +126 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/hooks.md +167 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/mcp.md +95 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/skills.md +175 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-acp.md +61 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-run.md +190 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-serve.md +239 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/workflows.md +664 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/agent-profile.md +548 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/hooks.md +602 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/opentelemetry.md +177 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/settings.md +245 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/themes.md +149 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/tool-kinds-and-names.md +58 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/tui-slash-commands.md +76 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/workflows.md +1005 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/start/getting-started.md +170 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/start/what-is-icode.md +34 -0
- chrys/app/tui/screens/guides/index.py +215 -0
- chrys/app/tui/screens/guides/reader.py +173 -0
- chrys/app/tui/screens/guides/screen.py +442 -0
- chrys/app/tui/screens/guides/screen.tcss +52 -0
- chrys/app/tui/screens/logs/__init__.py +7 -0
- chrys/app/tui/screens/logs/screen.py +504 -0
- chrys/app/tui/screens/logs/screen.tcss +45 -0
- chrys/app/tui/screens/main/__init__.py +7 -0
- chrys/app/tui/screens/main/action_availability.py +30 -0
- chrys/app/tui/screens/main/buddy_command.py +143 -0
- chrys/app/tui/screens/main/commands.py +1073 -0
- chrys/app/tui/screens/main/config_actions.py +464 -0
- chrys/app/tui/screens/main/copy_actions.py +117 -0
- chrys/app/tui/screens/main/dialog_controllers.py +826 -0
- chrys/app/tui/screens/main/dialog_gateway.py +166 -0
- chrys/app/tui/screens/main/diff_controller.py +478 -0
- chrys/app/tui/screens/main/engine_read_model.py +184 -0
- chrys/app/tui/screens/main/event_handlers.py +2014 -0
- chrys/app/tui/screens/main/input_flow.py +241 -0
- chrys/app/tui/screens/main/live_diff.py +244 -0
- chrys/app/tui/screens/main/main_screen_presenter.py +295 -0
- chrys/app/tui/screens/main/model_indicator.py +217 -0
- chrys/app/tui/screens/main/navigation.py +343 -0
- chrys/app/tui/screens/main/ports.py +571 -0
- chrys/app/tui/screens/main/recent_dirs.py +123 -0
- chrys/app/tui/screens/main/rollback_controller.py +586 -0
- chrys/app/tui/screens/main/runtime_info.py +71 -0
- chrys/app/tui/screens/main/screen.py +2265 -0
- chrys/app/tui/screens/main/screen.tcss +21 -0
- chrys/app/tui/screens/main/session_handlers.py +1127 -0
- chrys/app/tui/screens/main/session_title.py +239 -0
- chrys/app/tui/screens/main/settings_coordinator.py +365 -0
- chrys/app/tui/screens/main/settings_persistence.py +184 -0
- chrys/app/tui/screens/main/shell_mode.py +112 -0
- chrys/app/tui/screens/main/state.py +289 -0
- chrys/app/tui/screens/main/submit_state.py +11 -0
- chrys/app/tui/screens/main/subscriptions.py +177 -0
- chrys/app/tui/screens/main/suggestions.py +982 -0
- chrys/app/tui/screens/main/tool_action_bridge.py +75 -0
- chrys/app/tui/screens/main/view_adapter.py +1567 -0
- chrys/app/tui/screens/main/workflow_browser.py +747 -0
- chrys/app/tui/screens/main/workflow_content.py +248 -0
- chrys/app/tui/screens/main/workflow_controller.py +240 -0
- chrys/app/tui/screens/main/workflow_feedback.py +137 -0
- chrys/app/tui/screens/main/workflow_flow.py +49 -0
- chrys/app/tui/screens/main/workflow_run_control.py +456 -0
- chrys/app/tui/screens/main/workflow_session_view.py +316 -0
- chrys/app/tui/screens/main/workspace_actions.py +272 -0
- chrys/app/tui/screens/main/workspace_branch.py +194 -0
- chrys/app/tui/screens/menus/__init__.py +8 -0
- chrys/app/tui/screens/menus/languages.py +114 -0
- chrys/app/tui/screens/models/__init__.py +7 -0
- chrys/app/tui/screens/models/picker.py +147 -0
- chrys/app/tui/screens/models/screen.py +2043 -0
- chrys/app/tui/screens/models/screen.tcss +255 -0
- chrys/app/tui/screens/sessions/__init__.py +8 -0
- chrys/app/tui/screens/sessions/presenter.py +586 -0
- chrys/app/tui/screens/sessions/screen.py +779 -0
- chrys/app/tui/screens/sessions/screen.tcss +127 -0
- chrys/app/tui/screens/settings/__init__.py +29 -0
- chrys/app/tui/screens/settings/danger.py +26 -0
- chrys/app/tui/screens/settings/dialog.py +281 -0
- chrys/app/tui/screens/settings/layout.py +519 -0
- chrys/app/tui/screens/settings/migrate_dialog.py +253 -0
- chrys/app/tui/screens/settings/panes/__init__.py +3 -0
- chrys/app/tui/screens/settings/panes/notifications.py +248 -0
- chrys/app/tui/screens/settings/panes/sessions.py +148 -0
- chrys/app/tui/screens/settings/ports.py +55 -0
- chrys/app/tui/screens/settings/provenance.py +102 -0
- chrys/app/tui/screens/settings/rows.py +546 -0
- chrys/app/tui/screens/settings/settings.tcss +406 -0
- chrys/app/tui/screens/themes/__init__.py +8 -0
- chrys/app/tui/screens/themes/dialogs.py +330 -0
- chrys/app/tui/screens/themes/editor.py +632 -0
- chrys/app/tui/screens/themes/editor.tcss +268 -0
- chrys/app/tui/screens/themes/messages.py +95 -0
- chrys/app/tui/screens/themes/palette.py +694 -0
- chrys/app/tui/screens/themes/panel.py +113 -0
- chrys/app/tui/screens/themes/picker.py +203 -0
- chrys/app/tui/screens/themes/save.py +191 -0
- chrys/app/tui/support/__init__.py +3 -0
- chrys/app/tui/support/file_manager.py +64 -0
- chrys/app/tui/support/gc_freeze.py +1114 -0
- chrys/app/tui/support/path_shortcuts.py +50 -0
- chrys/app/tui/support/prompt_history.py +298 -0
- chrys/app/tui/support/workspace_mru.py +476 -0
- chrys/app/tui/terminal/__init__.py +6 -0
- chrys/app/tui/terminal/_pty_backend.py +114 -0
- chrys/app/tui/terminal/emulator/__init__.py +24 -0
- chrys/app/tui/terminal/emulator/buffer.py +456 -0
- chrys/app/tui/terminal/emulator/charsets.py +113 -0
- chrys/app/tui/terminal/emulator/core.py +963 -0
- chrys/app/tui/terminal/emulator/input.py +342 -0
- chrys/app/tui/terminal/emulator/parser.py +227 -0
- chrys/app/tui/terminal/emulator/pen.py +158 -0
- chrys/app/tui/terminal/launcher.py +455 -0
- chrys/app/tui/terminal/leaked_reports.py +44 -0
- chrys/app/tui/terminal/panel.py +323 -0
- chrys/app/tui/terminal/pty_process.py +405 -0
- chrys/app/tui/terminal/rendering.py +151 -0
- chrys/app/tui/terminal/shell.py +273 -0
- chrys/app/tui/terminal/shell_integration.py +199 -0
- chrys/app/tui/terminal/title.py +224 -0
- chrys/app/tui/terminal/widget.py +654 -0
- chrys/app/tui/theme.py +422 -0
- chrys/app/tui/theme_loader.py +201 -0
- chrys/app/tui/theme_stylesheet.py +49 -0
- chrys/app/tui/themes/__init__.py +3 -0
- chrys/app/tui/themes/document.py +120 -0
- chrys/app/tui/themes/preview.py +170 -0
- chrys/app/tui/themes/store.py +176 -0
- chrys/app/tui/toasts.py +69 -0
- chrys/app/tui/util/__init__.py +3 -0
- chrys/app/tui/util/context_pressure.py +146 -0
- chrys/app/tui/util/debug_log.py +292 -0
- chrys/app/tui/util/diff_entries.py +64 -0
- chrys/app/tui/util/formatting.py +53 -0
- chrys/app/tui/util/git_branch.py +326 -0
- chrys/app/tui/util/invocation_progress.py +57 -0
- chrys/app/tui/util/logo.py +32 -0
- chrys/app/tui/util/message_gate.py +35 -0
- chrys/app/tui/util/mutation_sources.py +14 -0
- chrys/app/tui/util/picker_text.py +27 -0
- chrys/app/tui/util/removal.py +47 -0
- chrys/app/tui/util/rich_style.py +36 -0
- chrys/app/tui/util/source_text.py +12 -0
- chrys/app/tui/util/static_update.py +88 -0
- chrys/app/tui/util/todo_format.py +51 -0
- chrys/app/tui/util/visibility.py +214 -0
- chrys/app/tui/widgets/__init__.py +60 -0
- chrys/app/tui/widgets/ask_user_controls.py +652 -0
- chrys/app/tui/widgets/ask_user_markdown.py +17 -0
- chrys/app/tui/widgets/ask_user_prompt.py +606 -0
- chrys/app/tui/widgets/buttons.py +52 -0
- chrys/app/tui/widgets/chat/__init__.py +3 -0
- chrys/app/tui/widgets/chat/agent_transcript_surface.py +818 -0
- chrys/app/tui/widgets/chat/chrome.py +296 -0
- chrys/app/tui/widgets/chat/compaction_card.py +353 -0
- chrys/app/tui/widgets/chat/context_fold.py +77 -0
- chrys/app/tui/widgets/chat/file_snapshot.py +91 -0
- chrys/app/tui/widgets/chat/image_preview.py +214 -0
- chrys/app/tui/widgets/chat/live_renderer.py +383 -0
- chrys/app/tui/widgets/chat/messages.py +1039 -0
- chrys/app/tui/widgets/chat/panel.py +1769 -0
- chrys/app/tui/widgets/chat/ports.py +245 -0
- chrys/app/tui/widgets/chat/renderers/__init__.py +7 -0
- chrys/app/tui/widgets/chat/renderers/ask_user.py +747 -0
- chrys/app/tui/widgets/chat/renderers/execute.py +431 -0
- chrys/app/tui/widgets/chat/renderers/file_edit.py +925 -0
- chrys/app/tui/widgets/chat/renderers/hosted_code.py +83 -0
- chrys/app/tui/widgets/chat/renderers/hosted_generic.py +330 -0
- chrys/app/tui/widgets/chat/renderers/hosted_image.py +107 -0
- chrys/app/tui/widgets/chat/renderers/hosted_mcp.py +43 -0
- chrys/app/tui/widgets/chat/renderers/hosted_search.py +167 -0
- chrys/app/tui/widgets/chat/renderers/hosted_shell.py +132 -0
- chrys/app/tui/widgets/chat/renderers/read_file.py +399 -0
- chrys/app/tui/widgets/chat/renderers/search.py +348 -0
- chrys/app/tui/widgets/chat/renderers/skill.py +564 -0
- chrys/app/tui/widgets/chat/renderers/sleep.py +287 -0
- chrys/app/tui/widgets/chat/renderers/sub_agent.py +1385 -0
- chrys/app/tui/widgets/chat/renderers/todo.py +114 -0
- chrys/app/tui/widgets/chat/renderers/web.py +69 -0
- chrys/app/tui/widgets/chat/replay.py +1605 -0
- chrys/app/tui/widgets/chat/replay_mount.py +322 -0
- chrys/app/tui/widgets/chat/scroll_controller.py +579 -0
- chrys/app/tui/widgets/chat/selection_controller.py +435 -0
- chrys/app/tui/widgets/chat/session_json.py +508 -0
- chrys/app/tui/widgets/chat/toc_model.py +156 -0
- chrys/app/tui/widgets/chat/tool_call.py +2478 -0
- chrys/app/tui/widgets/chat/tool_registry.py +753 -0
- chrys/app/tui/widgets/chat/tool_renderers.py +247 -0
- chrys/app/tui/widgets/chat/tool_view_builders.py +260 -0
- chrys/app/tui/widgets/chat/transcript_reader.py +57 -0
- chrys/app/tui/widgets/checkbox.py +24 -0
- chrys/app/tui/widgets/chrome/__init__.py +3 -0
- chrys/app/tui/widgets/chrome/app_header.py +283 -0
- chrys/app/tui/widgets/chrome/commands.py +95 -0
- chrys/app/tui/widgets/chrome/file_index.py +68 -0
- chrys/app/tui/widgets/chrome/file_scanner.py +670 -0
- chrys/app/tui/widgets/chrome/footer.py +284 -0
- chrys/app/tui/widgets/chrome/image_paste.py +351 -0
- chrys/app/tui/widgets/chrome/input_bar.py +1299 -0
- chrys/app/tui/widgets/chrome/status_bar.py +911 -0
- chrys/app/tui/widgets/chrome/suggestion_list.py +652 -0
- chrys/app/tui/widgets/click_affordance.py +24 -0
- chrys/app/tui/widgets/color_picker/__init__.py +254 -0
- chrys/app/tui/widgets/color_picker/controls.py +171 -0
- chrys/app/tui/widgets/color_picker/model.py +89 -0
- chrys/app/tui/widgets/dialog_buttons.py +58 -0
- chrys/app/tui/widgets/dialog_scroll.py +24 -0
- chrys/app/tui/widgets/diff_view/__init__.py +20 -0
- chrys/app/tui/widgets/diff_view/cells.py +59 -0
- chrys/app/tui/widgets/diff_view/code.py +280 -0
- chrys/app/tui/widgets/diff_view/compute.py +286 -0
- chrys/app/tui/widgets/diff_view/gutter.py +161 -0
- chrys/app/tui/widgets/diff_view/inline.py +77 -0
- chrys/app/tui/widgets/diff_view/palette.py +87 -0
- chrys/app/tui/widgets/diff_view/protocols.py +24 -0
- chrys/app/tui/widgets/diff_view/rows.py +138 -0
- chrys/app/tui/widgets/diff_view/unified.py +267 -0
- chrys/app/tui/widgets/diff_view/widget.py +209 -0
- chrys/app/tui/widgets/editor/__init__.py +79 -0
- chrys/app/tui/widgets/editor/coordinates.py +30 -0
- chrys/app/tui/widgets/editor/highlighter.py +139 -0
- chrys/app/tui/widgets/editor/keymaps.py +357 -0
- chrys/app/tui/widgets/editor/types.py +216 -0
- chrys/app/tui/widgets/editor/vim.py +1195 -0
- chrys/app/tui/widgets/editor/widget.py +401 -0
- chrys/app/tui/widgets/file_preview.py +58 -0
- chrys/app/tui/widgets/hatch.py +138 -0
- chrys/app/tui/widgets/input.py +66 -0
- chrys/app/tui/widgets/loading.py +125 -0
- chrys/app/tui/widgets/markdown/__init__.py +25 -0
- chrys/app/tui/widgets/markdown/_utils.py +21 -0
- chrys/app/tui/widgets/markdown/anchors.py +71 -0
- chrys/app/tui/widgets/markdown/blocks.py +115 -0
- chrys/app/tui/widgets/markdown/copyable.py +163 -0
- chrys/app/tui/widgets/markdown/diagram/__init__.py +35 -0
- chrys/app/tui/widgets/markdown/diagram/canvas.py +409 -0
- chrys/app/tui/widgets/markdown/diagram/charts.py +52 -0
- chrys/app/tui/widgets/markdown/diagram/diagnostics.py +101 -0
- chrys/app/tui/widgets/markdown/diagram/geometry.py +46 -0
- chrys/app/tui/widgets/markdown/diagram/layout.py +494 -0
- chrys/app/tui/widgets/markdown/diagram/messages.py +18 -0
- chrys/app/tui/widgets/markdown/diagram/model.py +275 -0
- chrys/app/tui/widgets/markdown/diagram/parser.py +173 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/__init__.py +3 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/charts.py +349 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/common.py +403 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/graphs.py +1072 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/planning.py +317 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/schedule.py +298 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/schemas.py +241 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/structure.py +221 -0
- chrys/app/tui/widgets/markdown/diagram/presentation.py +32 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/__init__.py +3 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/charts.py +275 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/common.py +73 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/planning.py +157 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/schedule.py +202 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/structure.py +77 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/xy.py +385 -0
- chrys/app/tui/widgets/markdown/diagram/router.py +651 -0
- chrys/app/tui/widgets/markdown/diagram/specs/__init__.py +3 -0
- chrys/app/tui/widgets/markdown/diagram/specs/charts.py +94 -0
- chrys/app/tui/widgets/markdown/diagram/specs/planning.py +68 -0
- chrys/app/tui/widgets/markdown/diagram/specs/schedule.py +65 -0
- chrys/app/tui/widgets/markdown/diagram/specs/structure.py +23 -0
- chrys/app/tui/widgets/markdown/diagram/viewer.py +92 -0
- chrys/app/tui/widgets/markdown/links.py +47 -0
- chrys/app/tui/widgets/markdown/math/__init__.py +36 -0
- chrys/app/tui/widgets/markdown/math/layout.py +739 -0
- chrys/app/tui/widgets/markdown/math/markdown.py +291 -0
- chrys/app/tui/widgets/markdown/math/parser.py +325 -0
- chrys/app/tui/widgets/markdown/math/symbols.py +325 -0
- chrys/app/tui/widgets/markdown/navigator.py +80 -0
- chrys/app/tui/widgets/markdown/parser.py +1057 -0
- chrys/app/tui/widgets/markdown/stream.py +73 -0
- chrys/app/tui/widgets/markdown/toc.py +98 -0
- chrys/app/tui/widgets/markdown/viewer.py +146 -0
- chrys/app/tui/widgets/markdown/widget.py +2046 -0
- chrys/app/tui/widgets/marquee.py +101 -0
- chrys/app/tui/widgets/option_menu.py +82 -0
- chrys/app/tui/widgets/page_navigator.py +118 -0
- chrys/app/tui/widgets/select.py +196 -0
- chrys/app/tui/widgets/selection.py +59 -0
- chrys/app/tui/widgets/sidebar/__init__.py +3 -0
- chrys/app/tui/widgets/sidebar/buddy.py +367 -0
- chrys/app/tui/widgets/sidebar/context.py +482 -0
- chrys/app/tui/widgets/sidebar/debug.py +195 -0
- chrys/app/tui/widgets/sidebar/empty_state.py +11 -0
- chrys/app/tui/widgets/sidebar/panel.py +198 -0
- chrys/app/tui/widgets/sidebar/tasks.py +198 -0
- chrys/app/tui/widgets/sidebar/toc.py +166 -0
- chrys/app/tui/widgets/sidebar/toc_types.py +30 -0
- chrys/app/tui/widgets/syntax_theme.py +85 -0
- chrys/app/tui/widgets/text_area.py +258 -0
- chrys/app/tui/widgets/trajectory/__init__.py +8 -0
- chrys/app/tui/widgets/trajectory/chartkit.py +264 -0
- chrys/app/tui/widgets/trajectory/insights.py +1266 -0
- chrys/app/tui/widgets/trajectory/overview.py +1101 -0
- chrys/app/tui/widgets/trajectory/panel.py +983 -0
- chrys/app/tui/widgets/trajectory/presentation.py +311 -0
- chrys/app/tui/widgets/trajectory/session_info.py +124 -0
- chrys/app/tui/widgets/trajectory/text_view.py +124 -0
- chrys/app/tui/widgets/trajectory/timeline.py +380 -0
- chrys/app/tui/widgets/welcome.py +126 -0
- chrys/app/tui/widgets/workflow/__init__.py +5 -0
- chrys/app/tui/widgets/workflow/edges.py +89 -0
- chrys/app/tui/widgets/workflow/graph.py +869 -0
- chrys/app/tui/widgets/workflow/info.py +310 -0
- chrys/app/tui/widgets/workflow/node_view.py +27 -0
- chrys/app/tui/widgets/workflow/output.py +225 -0
- chrys/app/tui/widgets/workflow/panel.py +658 -0
- chrys/app/tui/widgets/workflow/projector.py +324 -0
- chrys/app/tui/widgets/workflow/records.py +69 -0
- chrys/app/tui/widgets/workflow/scrollbar.py +82 -0
- chrys/app/tui/widgets/workflow/selection.py +151 -0
- chrys/app/tui/widgets/workflow/source.py +65 -0
- chrys/app/tui/widgets/workflow/text.py +257 -0
- chrys/app/tui/widgets/workflow/values.py +317 -0
- chrys/foundation/__init__.py +0 -0
- chrys/foundation/branding.py +15 -0
- chrys/foundation/config/__init__.py +7 -0
- chrys/foundation/config/coercion.py +374 -0
- chrys/foundation/config/context.py +34 -0
- chrys/foundation/config/env_file.py +141 -0
- chrys/foundation/config/env_layers.py +370 -0
- chrys/foundation/config/migrations.py +521 -0
- chrys/foundation/config/notification_events.py +22 -0
- chrys/foundation/config/process_settings.py +332 -0
- chrys/foundation/config/runtime_pointer.py +133 -0
- chrys/foundation/config/settings.py +1952 -0
- chrys/foundation/config/settings_store.py +996 -0
- chrys/foundation/config/spec.py +396 -0
- chrys/foundation/config/user_settings.py +140 -0
- chrys/foundation/config/warnings.py +262 -0
- chrys/foundation/config/web_values.py +135 -0
- chrys/foundation/config/yaml_store.py +487 -0
- chrys/foundation/errors/__init__.py +68 -0
- chrys/foundation/errors/_legacy.py +117 -0
- chrys/foundation/errors/_text.py +13 -0
- chrys/foundation/errors/_walk.py +85 -0
- chrys/foundation/errors/classify.py +278 -0
- chrys/foundation/errors/display.py +274 -0
- chrys/foundation/errors/formatting.py +283 -0
- chrys/foundation/errors/kinds.py +67 -0
- chrys/foundation/errors/network.py +497 -0
- chrys/foundation/errors/provider.py +445 -0
- chrys/foundation/errors/route.py +85 -0
- chrys/foundation/events/__init__.py +8 -0
- chrys/foundation/events/bus.py +143 -0
- chrys/foundation/events/types.py +1629 -0
- chrys/foundation/events/workflow.py +38 -0
- chrys/foundation/hosted_tools.py +142 -0
- chrys/foundation/i18n/__init__.py +32 -0
- chrys/foundation/i18n/_catalogs/zh-Hans/LC_MESSAGES/chrys.mo +0 -0
- chrys/foundation/i18n/catalogs.py +42 -0
- chrys/foundation/i18n/formatting.py +202 -0
- chrys/foundation/i18n/locale.py +92 -0
- chrys/foundation/i18n/localizer.py +187 -0
- chrys/foundation/i18n/messages.py +268 -0
- chrys/foundation/io/__init__.py +3 -0
- chrys/foundation/io/result_content.py +237 -0
- chrys/foundation/models/__init__.py +3 -0
- chrys/foundation/models/approval_reuse.py +23 -0
- chrys/foundation/models/ask_user.py +468 -0
- chrys/foundation/models/execution.py +18 -0
- chrys/foundation/models/history_markers.py +115 -0
- chrys/foundation/models/invocations.py +63 -0
- chrys/foundation/models/mutation_scope.py +28 -0
- chrys/foundation/models/session_env.py +87 -0
- chrys/foundation/models/session_surface.py +29 -0
- chrys/foundation/models/todos.py +74 -0
- chrys/foundation/models/turns.py +125 -0
- chrys/foundation/models/workflow_session.py +89 -0
- chrys/foundation/models/workspace.py +59 -0
- chrys/foundation/net/__init__.py +3 -0
- chrys/foundation/net/address_class.py +57 -0
- chrys/foundation/net/route_probe.py +94 -0
- chrys/foundation/net/url.py +107 -0
- chrys/foundation/observability/__init__.py +3 -0
- chrys/foundation/observability/exporters.py +174 -0
- chrys/foundation/observability/gate.py +31 -0
- chrys/foundation/observability/setup.py +497 -0
- chrys/foundation/observability/sink.py +228 -0
- chrys/foundation/patches/__init__.py +19 -0
- chrys/foundation/patches/mdurl_cache.py +59 -0
- chrys/foundation/patches/patcher.py +287 -0
- chrys/foundation/patches/staged_members.py +205 -0
- chrys/foundation/patches/textual_block_border.py +105 -0
- chrys/foundation/patches/textual_button_ansi.py +65 -0
- chrys/foundation/patches/textual_button_ansi_old.txt +68 -0
- chrys/foundation/patches/textual_callback_cache.py +248 -0
- chrys/foundation/patches/textual_callback_dispatch.py +109 -0
- chrys/foundation/patches/textual_compositor_cjk.py +566 -0
- chrys/foundation/patches/textual_dispatch_cache.py +150 -0
- chrys/foundation/patches/textual_ime_cursor_anchor.py +92 -0
- chrys/foundation/patches/textual_kitty_keyboard.py +268 -0
- chrys/foundation/patches/textual_lru_acyclic.py +241 -0
- chrys/foundation/patches/textual_message_pump.py +136 -0
- chrys/foundation/patches/textual_node_diet.py +875 -0
- chrys/foundation/patches/textual_one_shot_timer.py +48 -0
- chrys/foundation/patches/textual_option_list.py +90 -0
- chrys/foundation/patches/textual_precompose.py +89 -0
- chrys/foundation/patches/textual_pruned_tabs.py +69 -0
- chrys/foundation/patches/textual_reflow_reuse.py +1753 -0
- chrys/foundation/patches/textual_removed_node_caches.py +86 -0
- chrys/foundation/patches/textual_removed_screen_callbacks.py +55 -0
- chrys/foundation/patches/textual_selection_extract.py +48 -0
- chrys/foundation/patches/textual_strip_cycles.py +119 -0
- chrys/foundation/patches/textual_tab_selection.py +1611 -0
- chrys/foundation/patches/textual_timer_skip.py +70 -0
- chrys/foundation/patches/textual_utf8_decoder.py +106 -0
- chrys/foundation/patches/textual_win_sleep.py +167 -0
- chrys/foundation/patches/watchdog_fsevents.py +70 -0
- chrys/foundation/patches/watchdog_windows.py +52 -0
- chrys/foundation/platform/__init__.py +556 -0
- chrys/foundation/platform/c_api.py +32 -0
- chrys/foundation/platform/child_reap.py +107 -0
- chrys/foundation/platform/command_line.py +95 -0
- chrys/foundation/platform/files.py +1470 -0
- chrys/foundation/platform/output_capture.py +113 -0
- chrys/foundation/platform/paths.py +193 -0
- chrys/foundation/platform/process.py +1468 -0
- chrys/foundation/platform/pty_output.py +19 -0
- chrys/foundation/platform/runtime_paths.py +281 -0
- chrys/foundation/platform/win_console.py +129 -0
- chrys/foundation/reasoning_origin.py +67 -0
- chrys/foundation/recovery.py +16 -0
- chrys/foundation/retry.py +278 -0
- chrys/foundation/text/__init__.py +3 -0
- chrys/foundation/text/encoding.py +603 -0
- chrys/foundation/text/images.py +304 -0
- chrys/foundation/text/lines.py +24 -0
- chrys/foundation/text/mentions.py +90 -0
- chrys/foundation/text/model_json.py +25 -0
- chrys/foundation/text/reading_order.py +20 -0
- chrys/foundation/text/tokenizer.py +25 -0
- chrys/foundation/text/tool_output.py +287 -0
- chrys/foundation/text/yaml_io.py +62 -0
- chrys/foundation/tool_call_context.py +202 -0
- chrys/foundation/tool_execution_stamp.py +184 -0
- chrys/foundation/tool_invocation_order.py +48 -0
- chrys/foundation/tool_kinds.py +102 -0
- chrys/foundation/tool_result_metadata.py +287 -0
- chrys/foundation/trajectory/__init__.py +10 -0
- chrys/foundation/trajectory/context.py +481 -0
- chrys/foundation/trajectory/envelope.py +571 -0
- chrys/foundation/trajectory/event_types.py +294 -0
- chrys/foundation/trajectory/finalizers.py +46 -0
- chrys/foundation/trajectory/fingerprint.py +62 -0
- chrys/foundation/trajectory/ids.py +155 -0
- chrys/foundation/trajectory/keys.py +99 -0
- chrys/foundation/trajectory/lease.py +173 -0
- chrys/foundation/trajectory/metadata.py +72 -0
- chrys/foundation/trajectory/reader.py +271 -0
- chrys/foundation/trajectory/recovery.py +225 -0
- chrys/foundation/trajectory/revisions.py +152 -0
- chrys/foundation/trajectory/segments.py +225 -0
- chrys/foundation/trajectory/tools.py +117 -0
- chrys/foundation/trajectory/usage.py +151 -0
- chrys/foundation/trajectory/writer.py +972 -0
- chrys/foundation/trajectory_timing.py +97 -0
- chrys/foundation/util/__init__.py +3 -0
- chrys/foundation/util/async_tasks.py +29 -0
- chrys/foundation/util/chrys_headers.py +23 -0
- chrys/foundation/util/env_templates.py +104 -0
- chrys/foundation/util/filenames.py +96 -0
- chrys/foundation/util/header_charset.py +138 -0
- chrys/foundation/util/httpx_helpers.py +12 -0
- chrys/foundation/util/lock.py +236 -0
- chrys/foundation/util/once_close.py +46 -0
- chrys/foundation/util/session_ids.py +29 -0
- chrys/foundation/util/shell_tokens.py +88 -0
- chrys/foundation/util/sub_agent_context.py +38 -0
- chrys/foundation/util/time.py +35 -0
- chrys/foundation/util/unicode_scalars.py +36 -0
- chrys/foundation/vendor/__init__.py +43 -0
- chrys/foundation/vendor/ripgrep/rg-aarch64-apple-darwin +0 -0
- chrys/foundation/vendor/ripgrep/rg-aarch64-pc-windows-msvc.exe +0 -0
- chrys/foundation/vendor/ripgrep/rg-aarch64-unknown-linux-gnu +0 -0
- chrys/foundation/vendor/ripgrep/rg-x86_64-apple-darwin +0 -0
- chrys/foundation/vendor/ripgrep/rg-x86_64-pc-windows-msvc.exe +0 -0
- chrys/foundation/vendor/ripgrep/rg-x86_64-unknown-linux-musl +0 -0
- chrys/kernel/__init__.py +256 -0
- chrys/kernel/_content.py +1866 -0
- chrys/kernel/_loop_recorder.py +631 -0
- chrys/kernel/_null_overlay.py +1026 -0
- chrys/kernel/_result_ceiling.py +216 -0
- chrys/kernel/_serialization.py +431 -0
- chrys/kernel/_tool_arg_errors.py +1629 -0
- chrys/kernel/_tool_execution.py +1172 -0
- chrys/kernel/_tool_expansion.py +26 -0
- chrys/kernel/_types.py +2598 -0
- chrys/kernel/agent.py +994 -0
- chrys/kernel/client.py +1084 -0
- chrys/kernel/compaction.py +1315 -0
- chrys/kernel/exceptions.py +211 -0
- chrys/kernel/exchanges.py +683 -0
- chrys/kernel/identity.py +95 -0
- chrys/kernel/images.py +36 -0
- chrys/kernel/instrumentation.py +1618 -0
- chrys/kernel/loop.py +2308 -0
- chrys/kernel/middleware.py +616 -0
- chrys/kernel/sessions.py +604 -0
- chrys/kernel/tools.py +1061 -0
- chrys/kernel/types.py +126 -0
- chrys/orchestration/__init__.py +3 -0
- chrys/orchestration/engine/__init__.py +3 -0
- chrys/orchestration/engine/assembly.py +236 -0
- chrys/orchestration/engine/build/__init__.py +3 -0
- chrys/orchestration/engine/build/builder.py +1061 -0
- chrys/orchestration/engine/build/construction.py +408 -0
- chrys/orchestration/engine/build/loaded.py +139 -0
- chrys/orchestration/engine/engine.py +789 -0
- chrys/orchestration/engine/execution.py +771 -0
- chrys/orchestration/engine/loader.py +865 -0
- chrys/orchestration/engine/rollback.py +918 -0
- chrys/orchestration/engine/run/__init__.py +3 -0
- chrys/orchestration/engine/run/active_injection.py +419 -0
- chrys/orchestration/engine/run/attachments.py +519 -0
- chrys/orchestration/engine/run/bindings.py +1095 -0
- chrys/orchestration/engine/run/coordinator.py +1062 -0
- chrys/orchestration/engine/run/finalizer.py +417 -0
- chrys/orchestration/engine/run/input_refs.py +60 -0
- chrys/orchestration/engine/run/prompt_content.py +457 -0
- chrys/orchestration/engine/run/resume.py +299 -0
- chrys/orchestration/engine/run/retry.py +948 -0
- chrys/orchestration/engine/run/runner.py +625 -0
- chrys/orchestration/engine/run/runtime_skills.py +146 -0
- chrys/orchestration/engine/run/sub_agent_coordination.py +126 -0
- chrys/orchestration/engine/run/turn_hooks.py +258 -0
- chrys/orchestration/engine/run/turn_state.py +149 -0
- chrys/orchestration/engine/run/working_dir.py +50 -0
- chrys/orchestration/engine/session_lifecycle.py +2013 -0
- chrys/orchestration/engine/state/__init__.py +3 -0
- chrys/orchestration/engine/state/active_session.py +183 -0
- chrys/orchestration/engine/state/controls.py +639 -0
- chrys/orchestration/engine/state/current_agent.py +26 -0
- chrys/orchestration/engine/state/lifecycle_permits.py +395 -0
- chrys/orchestration/engine/state/machine.py +193 -0
- chrys/orchestration/engine/state/session_writer.py +434 -0
- chrys/orchestration/engine/trajectory.py +714 -0
- chrys/orchestration/engine/usage.py +118 -0
- chrys/orchestration/invoker/__init__.py +3 -0
- chrys/orchestration/invoker/acp.py +727 -0
- chrys/orchestration/invoker/acp_protocol.py +1115 -0
- chrys/orchestration/invoker/acp_spec.py +79 -0
- chrys/orchestration/invoker/attempts.py +994 -0
- chrys/orchestration/invoker/child_compaction.py +131 -0
- chrys/orchestration/invoker/child_history.py +99 -0
- chrys/orchestration/invoker/contracts.py +253 -0
- chrys/orchestration/invoker/evidence.py +94 -0
- chrys/orchestration/invoker/kernel.py +343 -0
- chrys/orchestration/invoker/origin.py +79 -0
- chrys/orchestration/invoker/resources.py +343 -0
- chrys/orchestration/invoker/runtime.py +299 -0
- chrys/orchestration/invoker/usage.py +80 -0
- chrys/orchestration/session_hooks.py +117 -0
- chrys/orchestration/session_host.py +1023 -0
- chrys/orchestration/session_resources.py +95 -0
- chrys/orchestration/session_usage.py +219 -0
- chrys/orchestration/startup.py +255 -0
- chrys/orchestration/sub_agents/__init__.py +3 -0
- chrys/orchestration/sub_agents/acp_policy.py +269 -0
- chrys/orchestration/sub_agents/kernel_policy.py +848 -0
- chrys/orchestration/sub_agents/registration.py +44 -0
- chrys/orchestration/sub_agents/shell.py +337 -0
- chrys/orchestration/sub_agents/tools.py +2228 -0
- chrys/orchestration/workflows/__init__.py +3 -0
- chrys/orchestration/workflows/agent_archive.py +156 -0
- chrys/orchestration/workflows/agent_node.py +894 -0
- chrys/orchestration/workflows/agent_node_build.py +687 -0
- chrys/orchestration/workflows/catalog.py +332 -0
- chrys/orchestration/workflows/coordinator.py +771 -0
- chrys/orchestration/workflows/hooks.py +176 -0
- chrys/orchestration/workflows/preview.py +322 -0
- chrys/orchestration/workflows/rollback.py +151 -0
- chrys/orchestration/workflows/runner.py +986 -0
- chrys/orchestration/workflows/session.py +390 -0
- chrys/orchestration/workflows/settings.py +97 -0
- chrys/orchestration/workflows/validation.py +674 -0
- chrys/orchestration/workflows/worker_client.py +1002 -0
- chrys/service/__init__.py +3 -0
- chrys/service/acp_client/__init__.py +65 -0
- chrys/service/acp_client/_transport.py +922 -0
- chrys/service/acp_client/client.py +1311 -0
- chrys/service/acp_client/errors.py +224 -0
- chrys/service/acp_client/protocol.py +220 -0
- chrys/service/acp_client/spawn.py +239 -0
- chrys/service/acp_client/spec.py +100 -0
- chrys/service/agent_middleware/__init__.py +60 -0
- chrys/service/agent_middleware/_metadata_keys.py +52 -0
- chrys/service/agent_middleware/control/__init__.py +3 -0
- chrys/service/agent_middleware/control/approval.py +769 -0
- chrys/service/agent_middleware/control/approval_hooks.py +62 -0
- chrys/service/agent_middleware/control/ask_user.py +207 -0
- chrys/service/agent_middleware/control/interrupt.py +50 -0
- chrys/service/agent_middleware/control/sleep.py +118 -0
- chrys/service/agent_middleware/control/todo.py +117 -0
- chrys/service/agent_middleware/events/__init__.py +3 -0
- chrys/service/agent_middleware/events/hook_dispatch.py +250 -0
- chrys/service/agent_middleware/events/hosted_tools.py +1762 -0
- chrys/service/agent_middleware/events/intermediate_text.py +128 -0
- chrys/service/agent_middleware/events/rejection_metadata.py +50 -0
- chrys/service/agent_middleware/events/result_persistence.py +98 -0
- chrys/service/agent_middleware/events/sub_agent_events.py +951 -0
- chrys/service/agent_middleware/events/tool_error_text.py +22 -0
- chrys/service/agent_middleware/events/tool_events.py +779 -0
- chrys/service/agent_middleware/injection.py +510 -0
- chrys/service/agent_middleware/reminders/__init__.py +91 -0
- chrys/service/agent_middleware/reminders/archive_pointer.py +154 -0
- chrys/service/agent_middleware/reminders/base.py +25 -0
- chrys/service/agent_middleware/reminders/context_usage.py +74 -0
- chrys/service/agent_middleware/reminders/file_change.py +63 -0
- chrys/service/agent_middleware/reminders/mcp.py +39 -0
- chrys/service/agent_middleware/reminders/profile_switch.py +106 -0
- chrys/service/agent_middleware/reminders/runtime_env.py +190 -0
- chrys/service/agent_middleware/reminders/skills.py +44 -0
- chrys/service/agent_middleware/reminders/sub_agents.py +35 -0
- chrys/service/agent_middleware/reminders/todo.py +35 -0
- chrys/service/agent_middleware/reminders/turn_line.py +48 -0
- chrys/service/agent_middleware/response_validation.py +1380 -0
- chrys/service/agent_middleware/system_reminder.py +1107 -0
- chrys/service/agent_middleware/validators.py +396 -0
- chrys/service/analytics/__init__.py +124 -0
- chrys/service/analytics/_actions.py +896 -0
- chrys/service/analytics/_context_evidence.py +357 -0
- chrys/service/analytics/_critical_path.py +179 -0
- chrys/service/analytics/_facts.py +919 -0
- chrys/service/analytics/_insights.py +769 -0
- chrys/service/analytics/_metric_ops.py +83 -0
- chrys/service/analytics/_session_projection.py +460 -0
- chrys/service/analytics/_timeline.py +434 -0
- chrys/service/analytics/_turn_graph.py +1237 -0
- chrys/service/analytics/_turns.py +1377 -0
- chrys/service/analytics/_workflows.py +171 -0
- chrys/service/analytics/aggregation.py +1474 -0
- chrys/service/analytics/classification.py +128 -0
- chrys/service/analytics/export.py +803 -0
- chrys/service/analytics/findings.py +282 -0
- chrys/service/analytics/math.py +79 -0
- chrys/service/analytics/model.py +886 -0
- chrys/service/analytics/reader.py +321 -0
- chrys/service/approval/__init__.py +3 -0
- chrys/service/approval/arbitration.py +102 -0
- chrys/service/approval/command_identity.py +109 -0
- chrys/service/approval/correlation.py +57 -0
- chrys/service/approval/grant_store.py +108 -0
- chrys/service/approval/judge.py +589 -0
- chrys/service/approval/level.py +15 -0
- chrys/service/approval/policy.py +209 -0
- chrys/service/approval/reuse.py +223 -0
- chrys/service/approval/reuse_binding.py +133 -0
- chrys/service/approval/safety_classifier.py +536 -0
- chrys/service/approval/turn_context.py +49 -0
- chrys/service/context/__init__.py +3 -0
- chrys/service/context/compaction/__init__.py +38 -0
- chrys/service/context/compaction/breaker.py +156 -0
- chrys/service/context/compaction/budgets.py +93 -0
- chrys/service/context/compaction/calibration.py +77 -0
- chrys/service/context/compaction/compression.py +690 -0
- chrys/service/context/compaction/current_turn_drop.py +458 -0
- chrys/service/context/compaction/events.py +201 -0
- chrys/service/context/compaction/exclusions.py +261 -0
- chrys/service/context/compaction/groups.py +361 -0
- chrys/service/context/compaction/last_words.py +1996 -0
- chrys/service/context/compaction/last_words_state.py +752 -0
- chrys/service/context/compaction/scoped.py +472 -0
- chrys/service/context/compaction/spill.py +1947 -0
- chrys/service/context/compaction/strategy.py +1116 -0
- chrys/service/context/compaction/summaries.py +319 -0
- chrys/service/context/compaction/turns.py +375 -0
- chrys/service/context/manager.py +174 -0
- chrys/service/context/memory_loader.py +792 -0
- chrys/service/context/middleware/__init__.py +3 -0
- chrys/service/context/middleware/usage.py +332 -0
- chrys/service/context/providers/__init__.py +3 -0
- chrys/service/context/providers/context_management.py +432 -0
- chrys/service/context/providers/history.py +647 -0
- chrys/service/context/providers/memory.py +50 -0
- chrys/service/context/tool_content.py +22 -0
- chrys/service/hooks/__init__.py +37 -0
- chrys/service/hooks/detached_worker.py +118 -0
- chrys/service/hooks/docs/README.md +14 -0
- chrys/service/hooks/docs/authoring.md +684 -0
- chrys/service/hooks/docs/configuration.md +499 -0
- chrys/service/hooks/docs/design.md +359 -0
- chrys/service/hooks/docs/project-hooks.md +348 -0
- chrys/service/hooks/events.py +157 -0
- chrys/service/hooks/loader.py +665 -0
- chrys/service/hooks/manager.py +807 -0
- chrys/service/hooks/matcher.py +111 -0
- chrys/service/hooks/outbox.py +294 -0
- chrys/service/hooks/runner.py +572 -0
- chrys/service/hooks/schema.py +407 -0
- chrys/service/llm/__init__.py +7 -0
- chrys/service/llm/_structured_outputs.py +192 -0
- chrys/service/llm/anthropic_messages/__init__.py +9 -0
- chrys/service/llm/anthropic_messages/client.py +254 -0
- chrys/service/llm/anthropic_messages/decode.py +331 -0
- chrys/service/llm/anthropic_messages/history.py +279 -0
- chrys/service/llm/anthropic_messages/request.py +323 -0
- chrys/service/llm/anthropic_messages/server_tools.py +319 -0
- chrys/service/llm/anthropic_messages/stream.py +297 -0
- chrys/service/llm/anthropic_messages/thinking_binding.py +156 -0
- chrys/service/llm/chat_completions/__init__.py +9 -0
- chrys/service/llm/chat_completions/client.py +369 -0
- chrys/service/llm/chat_completions/decode.py +338 -0
- chrys/service/llm/chat_completions/history.py +657 -0
- chrys/service/llm/chat_completions/reasoning.py +244 -0
- chrys/service/llm/chat_completions/request.py +192 -0
- chrys/service/llm/chat_completions/stream.py +546 -0
- chrys/service/llm/chat_completions/validation.py +308 -0
- chrys/service/llm/clients.py +613 -0
- chrys/service/llm/images.py +65 -0
- chrys/service/llm/mock.py +413 -0
- chrys/service/llm/observer.py +446 -0
- chrys/service/llm/one_shot.py +106 -0
- chrys/service/llm/openai_exceptions.py +93 -0
- chrys/service/llm/openai_responses/__init__.py +10 -0
- chrys/service/llm/openai_responses/client.py +323 -0
- chrys/service/llm/openai_responses/decode.py +432 -0
- chrys/service/llm/openai_responses/history.py +519 -0
- chrys/service/llm/openai_responses/hosted.py +625 -0
- chrys/service/llm/openai_responses/replay.py +629 -0
- chrys/service/llm/openai_responses/request.py +342 -0
- chrys/service/llm/openai_responses/stream.py +847 -0
- chrys/service/llm/openai_timestamps.py +57 -0
- chrys/service/llm/providers.py +107 -0
- chrys/service/llm/proxy_route.py +54 -0
- chrys/service/llm/raw_http_log.py +309 -0
- chrys/service/llm/route_facts.py +63 -0
- chrys/service/llm/route_sessions.py +49 -0
- chrys/service/llm/sdk_anthropic.py +18 -0
- chrys/service/llm/sdk_headers.py +47 -0
- chrys/service/llm/sdk_openai.py +18 -0
- chrys/service/llm/sdk_retry.py +59 -0
- chrys/service/llm/wire_client.py +246 -0
- chrys/service/mcp/__init__.py +3 -0
- chrys/service/mcp/_connection.py +235 -0
- chrys/service/mcp/_http_transport.py +350 -0
- chrys/service/mcp/_progressive.py +459 -0
- chrys/service/mcp/_stdio_transport.py +614 -0
- chrys/service/mcp/_tool_mixins.py +96 -0
- chrys/service/mcp/adapter.py +1031 -0
- chrys/service/mcp/cache.py +476 -0
- chrys/service/mcp/content.py +32 -0
- chrys/service/mcp/errors.py +169 -0
- chrys/service/mcp/owned.py +1330 -0
- chrys/service/mcp/result_limits.py +168 -0
- chrys/service/mcp/thinking_warning.py +95 -0
- chrys/service/mcp/validation.py +74 -0
- chrys/service/mutations/__init__.py +84 -0
- chrys/service/mutations/coordination.py +894 -0
- chrys/service/mutations/detector.py +458 -0
- chrys/service/mutations/git_calibrator.py +397 -0
- chrys/service/mutations/git_state.py +647 -0
- chrys/service/mutations/pipeline.py +779 -0
- chrys/service/mutations/scanner.py +466 -0
- chrys/service/mutations/snapshot_files.py +233 -0
- chrys/service/mutations/store.py +625 -0
- chrys/service/mutations/tool_names.py +15 -0
- chrys/service/mutations/trace.py +246 -0
- chrys/service/mutations/tracker.py +1289 -0
- chrys/service/mutations/types.py +559 -0
- chrys/service/mutations/workspace_changes.py +1583 -0
- chrys/service/profiles/__init__.py +2 -0
- chrys/service/profiles/agents/__init__.py +3 -0
- chrys/service/profiles/agents/builtins/Code.yaml +199 -0
- chrys/service/profiles/agents/builtins/Explore.yaml +62 -0
- chrys/service/profiles/agents/builtins/General.yaml +114 -0
- chrys/service/profiles/agents/builtins/QA.yaml +128 -0
- chrys/service/profiles/agents/loader.py +808 -0
- chrys/service/profiles/agents/registry.py +727 -0
- chrys/service/profiles/agents/schema.py +371 -0
- chrys/service/profiles/agents/serializer.py +196 -0
- chrys/service/profiles/coercion.py +22 -0
- chrys/service/profiles/models/__init__.py +3 -0
- chrys/service/profiles/models/env_bridge.py +157 -0
- chrys/service/profiles/models/loader.py +282 -0
- chrys/service/profiles/models/options.py +438 -0
- chrys/service/profiles/models/registry.py +104 -0
- chrys/service/profiles/models/resolver.py +286 -0
- chrys/service/profiles/models/schema.py +91 -0
- chrys/service/profiles/models/serializer.py +76 -0
- chrys/service/session/__init__.py +3 -0
- chrys/service/session/checkpoint.py +156 -0
- chrys/service/session/history.py +1616 -0
- chrys/service/session/message_metadata.py +151 -0
- chrys/service/session/persistence.py +435 -0
- chrys/service/session/runtime_metadata.py +210 -0
- chrys/service/session/sub_agent_logs.py +1069 -0
- chrys/service/session/sub_agent_transcript.py +654 -0
- chrys/service/skills/__init__.py +3 -0
- chrys/service/skills/adapter.py +408 -0
- chrys/service/skills/constants.py +8 -0
- chrys/service/skills/loader.py +575 -0
- chrys/service/skills/model.py +130 -0
- chrys/service/skills/provider.py +841 -0
- chrys/service/skills/runner.py +390 -0
- chrys/service/state/__init__.py +3 -0
- chrys/service/state/_fork.py +710 -0
- chrys/service/state/_session_files.py +175 -0
- chrys/service/state/_session_meta.py +552 -0
- chrys/service/state/locks.py +154 -0
- chrys/service/state/serializers.py +156 -0
- chrys/service/state/session_catalog.py +361 -0
- chrys/service/state/session_listing.py +84 -0
- chrys/service/state/session_migration.py +446 -0
- chrys/service/state/session_mru.py +315 -0
- chrys/service/state/store.py +2132 -0
- chrys/service/state/workflow.py +158 -0
- chrys/service/text_blocks.py +47 -0
- chrys/service/todos/__init__.py +3 -0
- chrys/service/todos/reminder.py +31 -0
- chrys/service/todos/tracker.py +58 -0
- chrys/service/tools/__init__.py +3 -0
- chrys/service/tools/approval_targets.py +92 -0
- chrys/service/tools/builtins/__init__.py +3 -0
- chrys/service/tools/builtins/ask_user.py +326 -0
- chrys/service/tools/builtins/doc_converter/__init__.py +494 -0
- chrys/service/tools/builtins/doc_converter/artifacts.py +392 -0
- chrys/service/tools/builtins/doc_converter/parsers/__init__.py +3 -0
- chrys/service/tools/builtins/doc_converter/parsers/_table.py +34 -0
- chrys/service/tools/builtins/doc_converter/parsers/base.py +101 -0
- chrys/service/tools/builtins/doc_converter/parsers/docx.py +88 -0
- chrys/service/tools/builtins/doc_converter/parsers/pdf.py +144 -0
- chrys/service/tools/builtins/doc_converter/parsers/pptx.py +103 -0
- chrys/service/tools/builtins/doc_converter/parsers/xls.py +32 -0
- chrys/service/tools/builtins/doc_converter/parsers/xlsx.py +51 -0
- chrys/service/tools/builtins/doc_converter/registry.py +55 -0
- chrys/service/tools/builtins/filesystem.py +1071 -0
- chrys/service/tools/builtins/search.py +1265 -0
- chrys/service/tools/builtins/shell.py +967 -0
- chrys/service/tools/builtins/shell_command_filtering/__init__.py +5 -0
- chrys/service/tools/builtins/shell_command_filtering/policy.py +60 -0
- chrys/service/tools/builtins/shell_command_filtering/presets.py +152 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/__init__.py +358 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/commands.py +416 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/git.py +408 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/syntax.py +87 -0
- chrys/service/tools/builtins/shell_command_filtering/tokenizer.py +214 -0
- chrys/service/tools/builtins/shell_filter.py +24 -0
- chrys/service/tools/builtins/sleep.py +91 -0
- chrys/service/tools/builtins/todo.py +64 -0
- chrys/service/tools/builtins/web/__init__.py +6 -0
- chrys/service/tools/builtins/web/build.py +268 -0
- chrys/service/tools/builtins/web/config.py +338 -0
- chrys/service/tools/builtins/web/credentials.py +37 -0
- chrys/service/tools/builtins/web/fetch/__init__.py +3 -0
- chrys/service/tools/builtins/web/fetch/cache.py +68 -0
- chrys/service/tools/builtins/web/fetch/convert.py +56 -0
- chrys/service/tools/builtins/web/fetch/tool.py +223 -0
- chrys/service/tools/builtins/web/hosted.py +61 -0
- chrys/service/tools/builtins/web/http.py +330 -0
- chrys/service/tools/builtins/web/progress.py +18 -0
- chrys/service/tools/builtins/web/search/__init__.py +3 -0
- chrys/service/tools/builtins/web/search/exa_mcp.py +146 -0
- chrys/service/tools/builtins/web/search/html.py +152 -0
- chrys/service/tools/builtins/web/search/json_api.py +227 -0
- chrys/service/tools/builtins/web/search/providers.py +77 -0
- chrys/service/tools/builtins/web/search/tool.py +218 -0
- chrys/service/tools/builtins/web/search/types.py +28 -0
- chrys/service/tools/builtins/web/tls_identity.py +66 -0
- chrys/service/tools/kinds.py +115 -0
- chrys/service/tools/names.py +47 -0
- chrys/service/tools/registry.py +242 -0
- chrys/service/tools/result_metadata.py +103 -0
- chrys/service/tools/session_artifacts.py +196 -0
- chrys/service/tools/spill.py +218 -0
- chrys/service/tools/workspace_paths.py +81 -0
- chrys/service/trajectory/__init__.py +11 -0
- chrys/service/trajectory/approvals.py +201 -0
- chrys/service/trajectory/compaction.py +420 -0
- chrys/service/trajectory/fork.py +75 -0
- chrys/service/trajectory/hooks.py +217 -0
- chrys/service/trajectory/items.py +41 -0
- chrys/service/trajectory/preparation.py +374 -0
- chrys/service/trajectory/retries.py +95 -0
- chrys/service/trajectory/revisions.py +129 -0
- chrys/service/trajectory/segmented.py +163 -0
- chrys/service/trajectory/session.py +762 -0
- chrys/service/trajectory/state.py +83 -0
- chrys/service/trajectory/sub_agents.py +169 -0
- chrys/service/trajectory/tombstone.py +262 -0
- chrys/service/trajectory/tools.py +323 -0
- chrys/service/trajectory/validation.py +130 -0
- chrys/service/trajectory/waits.py +161 -0
- chrys/service/trajectory/workflow.py +148 -0
- chrys/service/vision.py +128 -0
- chrys/service/workflows/__init__.py +3 -0
- chrys/service/workflows/admission.py +151 -0
- chrys/service/workflows/artifacts.py +109 -0
- chrys/service/workflows/asks.py +130 -0
- chrys/service/workflows/builtins/__init__.py +12 -0
- chrys/service/workflows/builtins/demo-workflow.manifest.json +635 -0
- chrys/service/workflows/builtins/demo-workflow.py +756 -0
- chrys/service/workflows/discovery.py +554 -0
- chrys/service/workflows/environment.py +284 -0
- chrys/service/workflows/graph.py +430 -0
- chrys/service/workflows/history.py +82 -0
- chrys/service/workflows/interpreter.py +107 -0
- chrys/service/workflows/journal.py +334 -0
- chrys/service/workflows/layout.py +56 -0
- chrys/service/workflows/ledger.py +149 -0
- chrys/service/workflows/model_selection.py +18 -0
- chrys/service/workflows/orphans.py +209 -0
- chrys/service/workflows/outcomes.py +46 -0
- chrys/service/workflows/protocol.py +210 -0
- chrys/service/workflows/records.py +142 -0
- chrys/service/workflows/scheduler.py +770 -0
- chrys/service/workflows/sdk/__init__.py +51 -0
- chrys/service/workflows/sdk/_ask.py +167 -0
- chrys/service/workflows/sdk/_builder.py +781 -0
- chrys/service/workflows/sdk/_values.py +92 -0
- chrys/service/workflows/sdk_artifact.py +74 -0
- chrys/service/workflows/store.py +494 -0
- chrys/service/workflows/transcript.py +102 -0
- chrys/service/workflows/values.py +73 -0
- chrys/service/workflows/worker_host.py +1820 -0
- chrys/workflows.py +38 -0
- icode_tui-0.29.1.dist-info/METADATA +104 -0
- icode_tui-0.29.1.dist-info/RECORD +1138 -0
- icode_tui-0.29.1.dist-info/WHEEL +4 -0
- icode_tui-0.29.1.dist-info/entry_points.txt +2 -0
- icode_tui-0.29.1.dist-info/licenses/LICENSE +202 -0
- icode_tui-0.29.1.dist-info/licenses/NOTICE +1955 -0
|
@@ -0,0 +1,1062 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Event-facing turn coordination for main-agent turns."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from collections.abc import Awaitable, Callable
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
12
|
+
from chrys.foundation.config.settings_store import SettingsHandle
|
|
13
|
+
from chrys.foundation.events.bus import EventBus
|
|
14
|
+
from chrys.foundation.events.types import (
|
|
15
|
+
Error,
|
|
16
|
+
InvocationAborted,
|
|
17
|
+
InvocationAbortRequested,
|
|
18
|
+
InvocationCascadeAborted,
|
|
19
|
+
InvocationPaused,
|
|
20
|
+
InvocationResumed,
|
|
21
|
+
InvocationRetryRequested,
|
|
22
|
+
UserInject,
|
|
23
|
+
UserInjectCancel,
|
|
24
|
+
UserInjectResult,
|
|
25
|
+
UserInterrupt,
|
|
26
|
+
UserMessage,
|
|
27
|
+
UserRetry,
|
|
28
|
+
Warning,
|
|
29
|
+
)
|
|
30
|
+
from chrys.foundation.i18n import msg
|
|
31
|
+
from chrys.foundation.models.execution import ExecutionSnapshot
|
|
32
|
+
from chrys.orchestration.engine.execution import (
|
|
33
|
+
CurrentRunInjectionWindow,
|
|
34
|
+
CurrentRunScope,
|
|
35
|
+
PreAdmissionPreparationEntry,
|
|
36
|
+
PreAdmissionPreparationTracker,
|
|
37
|
+
PromptAdmissionScope,
|
|
38
|
+
)
|
|
39
|
+
from chrys.orchestration.engine.loader import AgentLoader
|
|
40
|
+
from chrys.orchestration.engine.run import sub_agent_coordination
|
|
41
|
+
from chrys.orchestration.engine.run.active_injection import ActiveTurnInjector
|
|
42
|
+
from chrys.orchestration.engine.run.attachments import (
|
|
43
|
+
AttachmentDiscoveryResult,
|
|
44
|
+
discover_image_mentions,
|
|
45
|
+
discover_image_references,
|
|
46
|
+
load_image_attachments,
|
|
47
|
+
)
|
|
48
|
+
from chrys.orchestration.engine.run.finalizer import TurnFinalizer, _expire_current_run_scope
|
|
49
|
+
from chrys.orchestration.engine.run.prompt_content import PromptContentPreparer
|
|
50
|
+
from chrys.orchestration.engine.run.retry import RetryCoordinator
|
|
51
|
+
from chrys.orchestration.engine.run.runner import TurnRunner
|
|
52
|
+
from chrys.orchestration.engine.run.runtime_skills import RuntimeSkillRefresher
|
|
53
|
+
from chrys.orchestration.engine.run.turn_hooks import PromptSubmitGate, TurnHookDispatcher
|
|
54
|
+
from chrys.orchestration.engine.run.turn_state import CurrentTurnInput, TurnRuntimeState
|
|
55
|
+
from chrys.orchestration.engine.run.working_dir import refuse_while_working_dir_missing
|
|
56
|
+
from chrys.orchestration.engine.state.machine import EngineState, EngineStateMachine, Trigger
|
|
57
|
+
from chrys.orchestration.engine.state.session_writer import SessionWriter
|
|
58
|
+
from chrys.orchestration.engine.trajectory import TrajectoryRecorder
|
|
59
|
+
from chrys.orchestration.invoker.contracts import AbortCause
|
|
60
|
+
from chrys.orchestration.invoker.resources import TurnTaskBinding
|
|
61
|
+
from chrys.service.hooks.schema import HookDecision
|
|
62
|
+
from chrys.service.mutations.workspace_changes import WorkspaceChangeTracker
|
|
63
|
+
from chrys.service.session.history import SessionHistoryManager
|
|
64
|
+
from chrys.service.session.persistence import SessionPersistence
|
|
65
|
+
from chrys.service.trajectory.preparation import (
|
|
66
|
+
PreparationOutcome,
|
|
67
|
+
PreparationScope,
|
|
68
|
+
PreparationTrace,
|
|
69
|
+
input_admission_wait,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if TYPE_CHECKING:
|
|
73
|
+
from chrys.foundation.trajectory.context import TrajectoryContext
|
|
74
|
+
from chrys.orchestration.engine.state.active_session import ActiveSession
|
|
75
|
+
from chrys.orchestration.engine.state.current_agent import CurrentAgent
|
|
76
|
+
from chrys.orchestration.engine.state.lifecycle_permits import LifecyclePermits
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
_IMAGE_COMPRESSION_TIMEOUT_SECONDS = 30.0
|
|
80
|
+
|
|
81
|
+
_COORDINATOR_ENGINE_NOT_STARTED = msg(
|
|
82
|
+
"coordinator.engine_not_started",
|
|
83
|
+
fallback="Engine not started",
|
|
84
|
+
)
|
|
85
|
+
_COORDINATOR_INTERRUPT_IGNORED_LOADING = msg(
|
|
86
|
+
"coordinator.interrupt_ignored_loading",
|
|
87
|
+
fallback="Interrupt ignored while agent infrastructure is loading.",
|
|
88
|
+
)
|
|
89
|
+
_COORDINATOR_PROMPT_ADMISSION_CONFLICT = msg(
|
|
90
|
+
"coordinator.prompt_admission_conflict",
|
|
91
|
+
fallback="Prompt could not be admitted because another turn started.",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class TurnCoordinator:
|
|
96
|
+
"""Event-facing facade for one main-agent turn lifecycle.
|
|
97
|
+
|
|
98
|
+
Current queries re-read live values through current and session at each use.
|
|
99
|
+
Admission captures retain identities such as ActiveInjectionTarget,
|
|
100
|
+
CurrentRunScope, and RebuildControlToken across awaits and compare them
|
|
101
|
+
at their validation checkpoints.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def __init__(
|
|
105
|
+
self,
|
|
106
|
+
*,
|
|
107
|
+
turn_state: TurnRuntimeState,
|
|
108
|
+
current: CurrentAgent,
|
|
109
|
+
session: ActiveSession,
|
|
110
|
+
permits: LifecyclePermits,
|
|
111
|
+
writer: SessionWriter,
|
|
112
|
+
loader: AgentLoader,
|
|
113
|
+
hooks: TurnHookDispatcher,
|
|
114
|
+
bus: EventBus,
|
|
115
|
+
fsm: EngineStateMachine,
|
|
116
|
+
history: SessionHistoryManager,
|
|
117
|
+
trajectory_recorder: TrajectoryRecorder,
|
|
118
|
+
workspace_change_tracker: WorkspaceChangeTracker,
|
|
119
|
+
settings_handle: SettingsHandle,
|
|
120
|
+
persistence: SessionPersistence,
|
|
121
|
+
on_successful_turn: Callable[[], None],
|
|
122
|
+
on_turn_started: Callable[[], None],
|
|
123
|
+
prompt_content_preparer: PromptContentPreparer | None = None,
|
|
124
|
+
) -> None:
|
|
125
|
+
self._turn_state = turn_state
|
|
126
|
+
self._current = current
|
|
127
|
+
self._session = session
|
|
128
|
+
self._permits = permits
|
|
129
|
+
self._writer = writer
|
|
130
|
+
self._loader = loader
|
|
131
|
+
self._hooks = hooks
|
|
132
|
+
self._bus = bus
|
|
133
|
+
self._fsm = fsm
|
|
134
|
+
self._history = history
|
|
135
|
+
self._trajectory_recorder = trajectory_recorder
|
|
136
|
+
self._workspace_change_tracker = workspace_change_tracker
|
|
137
|
+
self._settings_handle = settings_handle
|
|
138
|
+
self._persistence = persistence
|
|
139
|
+
self._on_successful_turn = on_successful_turn
|
|
140
|
+
self._on_turn_started = on_turn_started
|
|
141
|
+
self._gate = PromptSubmitGate(session=self._session, current=self._current, bus=self._bus, fsm=self._fsm)
|
|
142
|
+
self._content = prompt_content_preparer or PromptContentPreparer(
|
|
143
|
+
session=self._session,
|
|
144
|
+
current=self._current,
|
|
145
|
+
bus=self._bus,
|
|
146
|
+
history=self._history,
|
|
147
|
+
fsm=self._fsm,
|
|
148
|
+
discover_mentions=discover_image_mentions,
|
|
149
|
+
discover_references=discover_image_references,
|
|
150
|
+
load_attachments=load_image_attachments,
|
|
151
|
+
compression_timeout_seconds=_IMAGE_COMPRESSION_TIMEOUT_SECONDS,
|
|
152
|
+
)
|
|
153
|
+
self._skills = RuntimeSkillRefresher(
|
|
154
|
+
current=self._current, loader=self._loader, session=self._session, bus=self._bus
|
|
155
|
+
)
|
|
156
|
+
self._injector = ActiveTurnInjector(
|
|
157
|
+
turn_state=self._turn_state,
|
|
158
|
+
current=self._current,
|
|
159
|
+
permits=self._permits,
|
|
160
|
+
session=self._session,
|
|
161
|
+
fsm=self._fsm,
|
|
162
|
+
bus=self._bus,
|
|
163
|
+
gate=self._gate,
|
|
164
|
+
content=self._content,
|
|
165
|
+
skills=self._skills,
|
|
166
|
+
)
|
|
167
|
+
self._finalizer = TurnFinalizer(
|
|
168
|
+
current=self._current,
|
|
169
|
+
session=self._session,
|
|
170
|
+
turn_state=self._turn_state,
|
|
171
|
+
writer=self._writer,
|
|
172
|
+
history=self._history,
|
|
173
|
+
trajectory_recorder=self._trajectory_recorder,
|
|
174
|
+
fsm=self._fsm,
|
|
175
|
+
workspace_change_tracker=self._workspace_change_tracker,
|
|
176
|
+
settings_handle=self._settings_handle,
|
|
177
|
+
bus=self._bus,
|
|
178
|
+
persistence=self._persistence,
|
|
179
|
+
on_successful_turn=self._on_successful_turn,
|
|
180
|
+
hooks=self._hooks,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def _runner(self) -> TurnRunner:
|
|
184
|
+
"""Create the service for one execution attempt."""
|
|
185
|
+
return TurnRunner(
|
|
186
|
+
current=self._current,
|
|
187
|
+
session=self._session,
|
|
188
|
+
turn_state=self._turn_state,
|
|
189
|
+
history=self._history,
|
|
190
|
+
workspace_change_tracker=self._workspace_change_tracker,
|
|
191
|
+
settings_handle=self._settings_handle,
|
|
192
|
+
trajectory_recorder=self._trajectory_recorder,
|
|
193
|
+
fsm=self._fsm,
|
|
194
|
+
on_turn_started=self._on_turn_started,
|
|
195
|
+
finalizer=self._finalizer,
|
|
196
|
+
hooks=self._hooks,
|
|
197
|
+
skills=self._skills,
|
|
198
|
+
content=self._content,
|
|
199
|
+
retry_factory=self._retry,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
def _retry(self) -> RetryCoordinator:
|
|
203
|
+
"""Create the service for one execution attempt."""
|
|
204
|
+
return RetryCoordinator(
|
|
205
|
+
turn_state=self._turn_state,
|
|
206
|
+
current=self._current,
|
|
207
|
+
permits=self._permits,
|
|
208
|
+
session=self._session,
|
|
209
|
+
fsm=self._fsm,
|
|
210
|
+
history=self._history,
|
|
211
|
+
bus=self._bus,
|
|
212
|
+
trajectory_recorder=self._trajectory_recorder,
|
|
213
|
+
gate=self._gate,
|
|
214
|
+
injector=self._injector,
|
|
215
|
+
content=self._content,
|
|
216
|
+
skills=self._skills,
|
|
217
|
+
retry_and_save=self.retry_and_save,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def turn_state(self) -> TurnRuntimeState:
|
|
222
|
+
"""The runtime state shared with lifecycle operations."""
|
|
223
|
+
return self._turn_state
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def run_task(self) -> asyncio.Task[None] | None:
|
|
227
|
+
"""Current run task, including a retry task installed during finalization."""
|
|
228
|
+
return self._turn_state.lease.run_task
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def current_input(self) -> CurrentTurnInput:
|
|
232
|
+
"""Current prompt data used by crash-recovery checkpoint writes."""
|
|
233
|
+
return self._turn_state.current_input
|
|
234
|
+
|
|
235
|
+
@property
|
|
236
|
+
def is_turn_active(self) -> bool:
|
|
237
|
+
"""Return whether the FSM currently admits active-turn injection."""
|
|
238
|
+
return self._fsm.is_running()
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def is_turn_lifecycle_active(self) -> bool:
|
|
242
|
+
"""Return whether execution or post-run finalization is still in flight."""
|
|
243
|
+
return self._turn_state.lease.execution_busy()
|
|
244
|
+
|
|
245
|
+
def was_run_task_finally_saved(self, task: asyncio.Task[None]) -> bool:
|
|
246
|
+
"""Return whether *task* completed the durable final session save."""
|
|
247
|
+
return self._turn_state.lease.was_run_task_finally_saved(task)
|
|
248
|
+
|
|
249
|
+
def clear_run_task(self) -> None:
|
|
250
|
+
"""Clear the visible run task after shutdown has drained or cancelled it."""
|
|
251
|
+
self._turn_state.lease.release_run_task()
|
|
252
|
+
|
|
253
|
+
async def wait_for_run_task(self) -> None:
|
|
254
|
+
"""Wait for the active run-task chain, preserving task failure semantics."""
|
|
255
|
+
await self._turn_state.lease.observe_run_task_chain(propagate_inner_cancel=True)
|
|
256
|
+
await self._turn_state.lease.settle_notifications()
|
|
257
|
+
|
|
258
|
+
async def run_fresh(
|
|
259
|
+
self,
|
|
260
|
+
text: str,
|
|
261
|
+
created_at: datetime | str | None = None,
|
|
262
|
+
contents: list[Any] | None = None,
|
|
263
|
+
*,
|
|
264
|
+
run_scope: CurrentRunScope | None = None,
|
|
265
|
+
injection_window: CurrentRunInjectionWindow | None = None,
|
|
266
|
+
admission_preparation: PreparationTrace | None = None,
|
|
267
|
+
binding_failure: Exception | None = None,
|
|
268
|
+
) -> None:
|
|
269
|
+
"""Execute a fresh agent pass against the current engine state."""
|
|
270
|
+
|
|
271
|
+
await self._runner().run_fresh(
|
|
272
|
+
text,
|
|
273
|
+
created_at=created_at,
|
|
274
|
+
contents=contents,
|
|
275
|
+
run_scope=run_scope,
|
|
276
|
+
injection_window=injection_window,
|
|
277
|
+
admission_preparation=admission_preparation,
|
|
278
|
+
binding_failure=binding_failure,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
async def run_retry(
|
|
282
|
+
self,
|
|
283
|
+
additional_text: str = "",
|
|
284
|
+
created_at: datetime | str | None = None,
|
|
285
|
+
*,
|
|
286
|
+
run_scope: CurrentRunScope | None = None,
|
|
287
|
+
injection_window: CurrentRunInjectionWindow | None = None,
|
|
288
|
+
admission_preparation: PreparationTrace | None = None,
|
|
289
|
+
binding_failure: Exception | None = None,
|
|
290
|
+
) -> None:
|
|
291
|
+
"""Execute a retry/resume pass against the current engine state."""
|
|
292
|
+
|
|
293
|
+
await self._runner().run_retry(
|
|
294
|
+
additional_text,
|
|
295
|
+
created_at=created_at,
|
|
296
|
+
run_scope=run_scope,
|
|
297
|
+
injection_window=injection_window,
|
|
298
|
+
admission_preparation=admission_preparation,
|
|
299
|
+
binding_failure=binding_failure,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
async def finalize_current_run(self) -> None:
|
|
303
|
+
"""Finalize the current executor pass against the current engine state."""
|
|
304
|
+
|
|
305
|
+
await self._runner().finalize_current_run()
|
|
306
|
+
|
|
307
|
+
async def on_user_message(self, event: UserMessage) -> None:
|
|
308
|
+
"""Handle a user message by running the executor as an async task.
|
|
309
|
+
|
|
310
|
+
On accepted fresh turns, mutates ``event.prepared_contents`` before
|
|
311
|
+
returning so sequential ``EventBus.publish`` callers can render the exact
|
|
312
|
+
multimodal payload that will be sent to the model.
|
|
313
|
+
"""
|
|
314
|
+
if await self._turn_state.lease.refuse_while_workflow_active(self._bus, self._session.session_id):
|
|
315
|
+
return
|
|
316
|
+
# Track injection-identified submits so a concurrent cancel knows an
|
|
317
|
+
# admission is still in flight to observe its mark (no-op for None).
|
|
318
|
+
turn_state = self._turn_state
|
|
319
|
+
turn_state.begin_inflight_injection(event.injection_id)
|
|
320
|
+
preparation_tracker = PreAdmissionPreparationTracker()
|
|
321
|
+
handed_off = False
|
|
322
|
+
try:
|
|
323
|
+
await self._start_pre_admission_preparation(preparation_tracker)
|
|
324
|
+
handed_off = await self._admit_user_message(event, preparation_tracker=preparation_tracker)
|
|
325
|
+
except asyncio.CancelledError:
|
|
326
|
+
preparation = preparation_tracker.preparation
|
|
327
|
+
if (
|
|
328
|
+
preparation is not None
|
|
329
|
+
and not preparation_tracker.preparation_handed_off
|
|
330
|
+
and not preparation.finished_state
|
|
331
|
+
):
|
|
332
|
+
preparation.finished_soon(outcome=PreparationOutcome.CANCELLED)
|
|
333
|
+
raise
|
|
334
|
+
except BaseException:
|
|
335
|
+
preparation = preparation_tracker.preparation
|
|
336
|
+
if (
|
|
337
|
+
preparation is not None
|
|
338
|
+
and not preparation_tracker.preparation_handed_off
|
|
339
|
+
and not preparation.finished_state
|
|
340
|
+
):
|
|
341
|
+
preparation.finished_soon(outcome=PreparationOutcome.PREPARATION_FAILED)
|
|
342
|
+
raise
|
|
343
|
+
finally:
|
|
344
|
+
turn_state.lease.deregister_pre_admission_preparation(preparation_tracker.current)
|
|
345
|
+
turn_state.finish_inflight_injection(event.injection_id)
|
|
346
|
+
preparation = preparation_tracker.preparation
|
|
347
|
+
if (
|
|
348
|
+
preparation is not None
|
|
349
|
+
and not handed_off
|
|
350
|
+
and not preparation_tracker.preparation_handed_off
|
|
351
|
+
and not preparation.finished_state
|
|
352
|
+
):
|
|
353
|
+
await preparation.finished(outcome=PreparationOutcome.PREPARATION_FAILED)
|
|
354
|
+
|
|
355
|
+
async def _admit_user_message(
|
|
356
|
+
self,
|
|
357
|
+
event: UserMessage,
|
|
358
|
+
*,
|
|
359
|
+
preparation_tracker: PreAdmissionPreparationTracker,
|
|
360
|
+
) -> bool:
|
|
361
|
+
"""Admit one message and report whether its preparation changed owners."""
|
|
362
|
+
admission: PromptAdmissionScope | None = None
|
|
363
|
+
admission_released = False
|
|
364
|
+
while True:
|
|
365
|
+
await self._wait_for_pre_admission_gate(self._permits.wait_for_agent_load_idle, preparation_tracker)
|
|
366
|
+
preparation = preparation_tracker.preparation
|
|
367
|
+
if self._current.loaded is None:
|
|
368
|
+
if self._turn_state.lease.prompt_admission_closed:
|
|
369
|
+
await self._wait_for_pre_admission_gate(
|
|
370
|
+
self._turn_state.lease.wait_for_prompt_admission_open,
|
|
371
|
+
preparation_tracker,
|
|
372
|
+
)
|
|
373
|
+
continue
|
|
374
|
+
await self._bus.publish(
|
|
375
|
+
Error(
|
|
376
|
+
code="not_ready",
|
|
377
|
+
message="Engine not started",
|
|
378
|
+
display_message=_COORDINATOR_ENGINE_NOT_STARTED.bind(),
|
|
379
|
+
session_id=self._session.session_id,
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
if preparation is not None:
|
|
383
|
+
await preparation.finished(outcome=PreparationOutcome.NOT_READY)
|
|
384
|
+
return False
|
|
385
|
+
|
|
386
|
+
# A run is in-flight — FSM covers RUNNING, PENDING_RETRY, and
|
|
387
|
+
# AWAITING_SUB_AGENTS (parent task pinned on a sub-agent's
|
|
388
|
+
# ``pending_decision`` future). Gate on the FSM so the intent
|
|
389
|
+
# travels with the state contract, not with the executor's
|
|
390
|
+
# ``_running`` implementation detail — a new state that should
|
|
391
|
+
# also inject only has to be added to
|
|
392
|
+
# :meth:`EngineStateMachine.is_running` to be covered here.
|
|
393
|
+
if self._fsm.is_running():
|
|
394
|
+
return await self._injector.inject(
|
|
395
|
+
event.text,
|
|
396
|
+
created_at=event.timestamp,
|
|
397
|
+
route="fsm_active",
|
|
398
|
+
reject_images_without_target=True,
|
|
399
|
+
injection_id=event.injection_id,
|
|
400
|
+
preparation=preparation,
|
|
401
|
+
preparation_tracker=preparation_tracker,
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# If a previous run task is still cleaning up (e.g., interrupt teardown),
|
|
405
|
+
# wait for it to finish before starting a new run. Without this, the
|
|
406
|
+
# message would be injected into the dying run and then drained/lost.
|
|
407
|
+
if self._turn_state.lease.run_task is not None and not self._turn_state.lease.run_task.done():
|
|
408
|
+
if self._current.loaded.bindings.state.running:
|
|
409
|
+
# TurnBindings is actively running (not just cleaning up) — inject
|
|
410
|
+
return await self._injector.inject(
|
|
411
|
+
event.text,
|
|
412
|
+
created_at=event.timestamp,
|
|
413
|
+
route="executor_fallback",
|
|
414
|
+
reject_images_without_target=True,
|
|
415
|
+
injection_id=event.injection_id,
|
|
416
|
+
preparation=preparation,
|
|
417
|
+
preparation_tracker=preparation_tracker,
|
|
418
|
+
)
|
|
419
|
+
# TurnBindings finished but _post_run() is still running (session
|
|
420
|
+
# save, FSM transition). Wait for cleanup to complete so the
|
|
421
|
+
# new run starts from a clean state.
|
|
422
|
+
await self._wait_for_pre_admission_gate(self._wait_for_existing_run_task, preparation_tracker)
|
|
423
|
+
preparation = preparation_tracker.preparation
|
|
424
|
+
|
|
425
|
+
if self._turn_state.lease.prompt_admission_closed:
|
|
426
|
+
await self._wait_for_pre_admission_gate(
|
|
427
|
+
self._turn_state.lease.wait_for_prompt_admission_open,
|
|
428
|
+
preparation_tracker,
|
|
429
|
+
)
|
|
430
|
+
continue
|
|
431
|
+
if self._turn_state.lease.active_admission_count() > 0:
|
|
432
|
+
await self._wait_for_pre_admission_gate(
|
|
433
|
+
self._turn_state.lease.wait_for_active_admissions_idle,
|
|
434
|
+
preparation_tracker,
|
|
435
|
+
)
|
|
436
|
+
continue
|
|
437
|
+
if await refuse_while_working_dir_missing(self._bus, self._session):
|
|
438
|
+
if preparation is not None:
|
|
439
|
+
await preparation.finished(outcome=PreparationOutcome.REJECTED)
|
|
440
|
+
return False
|
|
441
|
+
# A workflow run may have taken the lease while this message was preparing.
|
|
442
|
+
if await self._turn_state.lease.refuse_while_workflow_active(self._bus, self._session.session_id):
|
|
443
|
+
if preparation is not None:
|
|
444
|
+
await preparation.finished(outcome=PreparationOutcome.REJECTED)
|
|
445
|
+
return False
|
|
446
|
+
admission = self._turn_state.lease.reserve_prompt_admission(
|
|
447
|
+
kind="fresh",
|
|
448
|
+
session_generation=self._permits.session_generation,
|
|
449
|
+
build_generation=self._permits.build_generation,
|
|
450
|
+
preparation_trace=preparation,
|
|
451
|
+
)
|
|
452
|
+
if admission is None:
|
|
453
|
+
await self._wait_for_pre_admission_gate(
|
|
454
|
+
self._turn_state.lease.wait_for_prompt_admission_open,
|
|
455
|
+
preparation_tracker,
|
|
456
|
+
)
|
|
457
|
+
continue
|
|
458
|
+
self._turn_state.lease.deregister_pre_admission_preparation(preparation_tracker.current)
|
|
459
|
+
break
|
|
460
|
+
|
|
461
|
+
try:
|
|
462
|
+
# A locked-input submit can outlive its run and arrive here as a
|
|
463
|
+
# fresh turn; honor a cancel that landed while it waited so Esc
|
|
464
|
+
# never lets the withdrawn text start a new turn.
|
|
465
|
+
if await self._abandon_cancelled_injection_submit(event):
|
|
466
|
+
if preparation is not None:
|
|
467
|
+
await preparation.finished(outcome=PreparationOutcome.CANCELLED)
|
|
468
|
+
return False
|
|
469
|
+
admission_session_id = self._session.session_id
|
|
470
|
+
decision = await self._evaluate_user_prompt_submit(
|
|
471
|
+
event.text,
|
|
472
|
+
injected=False,
|
|
473
|
+
target_operation_id=preparation.committed_operation_id if preparation is not None else None,
|
|
474
|
+
trajectory_context=preparation.context if preparation is not None else None,
|
|
475
|
+
)
|
|
476
|
+
if not self._admission_owner_is_current(admission):
|
|
477
|
+
if preparation is not None:
|
|
478
|
+
await preparation.finished(outcome=PreparationOutcome.OWNER_CHANGED)
|
|
479
|
+
return False
|
|
480
|
+
if await self._handle_user_prompt_submit_decision(decision, injected=False):
|
|
481
|
+
if preparation is not None:
|
|
482
|
+
await preparation.finished(outcome=PreparationOutcome.REJECTED)
|
|
483
|
+
return False
|
|
484
|
+
|
|
485
|
+
if event.prepared_contents is not None:
|
|
486
|
+
contents = list(event.prepared_contents)
|
|
487
|
+
if await self.reject_text_only_prepared_contents(
|
|
488
|
+
event.text,
|
|
489
|
+
contents,
|
|
490
|
+
admission=admission,
|
|
491
|
+
event_session_id=admission_session_id,
|
|
492
|
+
):
|
|
493
|
+
if preparation is not None:
|
|
494
|
+
await preparation.finished(outcome=PreparationOutcome.IMAGE_REJECTED)
|
|
495
|
+
return False
|
|
496
|
+
else:
|
|
497
|
+
contents = await self.prepare_user_contents(
|
|
498
|
+
event.text,
|
|
499
|
+
admission=admission,
|
|
500
|
+
event_session_id=admission_session_id,
|
|
501
|
+
)
|
|
502
|
+
if contents is None:
|
|
503
|
+
if preparation is not None:
|
|
504
|
+
await preparation.finished(outcome=PreparationOutcome.PREPARATION_FAILED)
|
|
505
|
+
return False
|
|
506
|
+
event.prepared_contents = contents
|
|
507
|
+
if not self._admission_owner_is_current(admission):
|
|
508
|
+
if preparation is not None:
|
|
509
|
+
await preparation.finished(outcome=PreparationOutcome.OWNER_CHANGED)
|
|
510
|
+
return False
|
|
511
|
+
|
|
512
|
+
# Final cancel check after all awaited preparation; task creation
|
|
513
|
+
# below is synchronous, so a cancel can no longer interleave.
|
|
514
|
+
if await self._abandon_cancelled_injection_submit(event):
|
|
515
|
+
if preparation is not None:
|
|
516
|
+
await preparation.finished(outcome=PreparationOutcome.CANCELLED)
|
|
517
|
+
return False
|
|
518
|
+
if not self._fresh_prompt_fsm_accepts():
|
|
519
|
+
await self._publish_prompt_admission_conflict()
|
|
520
|
+
if preparation is not None:
|
|
521
|
+
await preparation.finished(outcome=PreparationOutcome.CONFLICT)
|
|
522
|
+
return False
|
|
523
|
+
if self._turn_state.lease.run_task is not None and not self._turn_state.lease.run_task.done():
|
|
524
|
+
await self._publish_prompt_admission_conflict()
|
|
525
|
+
if preparation is not None:
|
|
526
|
+
await preparation.finished(outcome=PreparationOutcome.CONFLICT)
|
|
527
|
+
return False
|
|
528
|
+
_expire_current_run_scope(self._turn_state, self._current, self._turn_state.lease.current_run_scope)
|
|
529
|
+
|
|
530
|
+
# After a failed/interrupted run, remove status markers (interrupted,
|
|
531
|
+
# error, turn_marker) so the new message appends cleanly. Then remove
|
|
532
|
+
# any orphaned user message that got no model response (e.g. immediate
|
|
533
|
+
# 401 error) — this matches the live UX where the failed message
|
|
534
|
+
# disappeared when the user typed a new one. If the model DID produce
|
|
535
|
+
# output (tool calls, partial text) the user message is preserved.
|
|
536
|
+
#
|
|
537
|
+
# Also check the history itself for trailing error markers — after a
|
|
538
|
+
# session restore the FSM is reset to IDLE, but the saved history
|
|
539
|
+
# still carries the error state from the previous run.
|
|
540
|
+
if (
|
|
541
|
+
self._fsm.state in (EngineState.INTERRUPTED, EngineState.FAILED)
|
|
542
|
+
or self._history.has_trailing_error_markers()
|
|
543
|
+
):
|
|
544
|
+
self._history.remove_trailing_markers()
|
|
545
|
+
self._history.remove_orphaned_user_message()
|
|
546
|
+
|
|
547
|
+
reminder_middleware = self._current.loaded.reminder_middleware if self._current.loaded is not None else None
|
|
548
|
+
if reminder_middleware is None:
|
|
549
|
+
self._turn_state.lease.release_prompt_admission(admission)
|
|
550
|
+
admission_released = True
|
|
551
|
+
self._fsm.try_transition(Trigger.USER_MESSAGE)
|
|
552
|
+
self._turn_state.lease.run_task = asyncio.create_task(
|
|
553
|
+
self.run_and_save(
|
|
554
|
+
event.text,
|
|
555
|
+
created_at=event.timestamp,
|
|
556
|
+
contents=contents,
|
|
557
|
+
admission_preparation=preparation,
|
|
558
|
+
)
|
|
559
|
+
)
|
|
560
|
+
# Record the opener synchronously with its task: a Stop followed by
|
|
561
|
+
# Retry must find it even before preparation has populated history.
|
|
562
|
+
self._turn_state.set_current_input(event.text, contents, event.timestamp)
|
|
563
|
+
self._queue_prompt_hook_reminders(decision, injected=False)
|
|
564
|
+
return True
|
|
565
|
+
|
|
566
|
+
reminder_scope = reminder_middleware.create_current_run_scope()
|
|
567
|
+
promotion = self._turn_state.lease.promote_fresh_admission_to_run(
|
|
568
|
+
admission,
|
|
569
|
+
reminder_scope=reminder_scope,
|
|
570
|
+
make_task=lambda scope, window: asyncio.create_task(
|
|
571
|
+
self.run_and_save(
|
|
572
|
+
event.text,
|
|
573
|
+
created_at=event.timestamp,
|
|
574
|
+
contents=contents,
|
|
575
|
+
run_scope=scope,
|
|
576
|
+
injection_window=window,
|
|
577
|
+
admission_preparation=preparation,
|
|
578
|
+
)
|
|
579
|
+
),
|
|
580
|
+
)
|
|
581
|
+
if not promotion.promoted:
|
|
582
|
+
reminder_middleware.expire_current_run_scope(reminder_scope)
|
|
583
|
+
if promotion.conflict:
|
|
584
|
+
await self._publish_prompt_admission_conflict()
|
|
585
|
+
if preparation is not None:
|
|
586
|
+
await preparation.finished(
|
|
587
|
+
outcome=PreparationOutcome.CONFLICT if promotion.conflict else PreparationOutcome.OWNER_CHANGED
|
|
588
|
+
)
|
|
589
|
+
return False
|
|
590
|
+
admission_released = True
|
|
591
|
+
# Record the opener synchronously with its task: a Stop followed by
|
|
592
|
+
# Retry must find it even before preparation has populated history.
|
|
593
|
+
self._turn_state.set_current_input(event.text, contents, event.timestamp)
|
|
594
|
+
self._fsm.try_transition(Trigger.USER_MESSAGE)
|
|
595
|
+
self._queue_prompt_hook_reminders(decision, injected=False)
|
|
596
|
+
return True
|
|
597
|
+
finally:
|
|
598
|
+
if admission is not None and not admission_released:
|
|
599
|
+
self._turn_state.lease.release_prompt_admission(admission)
|
|
600
|
+
|
|
601
|
+
async def on_user_interrupt(self, _event: UserInterrupt) -> None:
|
|
602
|
+
"""Handle user interrupt.
|
|
603
|
+
|
|
604
|
+
Cascades to every live sub-agent controller first so paused
|
|
605
|
+
sub-agents resolve via the cascade-abort branch (otherwise their
|
|
606
|
+
``pending_decision`` future would keep their ``_invoke``
|
|
607
|
+
coroutine pinned forever and the subsequent task cancel below
|
|
608
|
+
would leak). Then sets the interrupt flag / cancels the parent
|
|
609
|
+
task. It then either binds cancellation to the exact pre-executor
|
|
610
|
+
run task or interrupts the active executor; ``run_and_save``
|
|
611
|
+
detects ``was_interrupted`` and rolls back history.
|
|
612
|
+
"""
|
|
613
|
+
if self._permits.agent_loading:
|
|
614
|
+
await self._bus.publish(
|
|
615
|
+
Warning(
|
|
616
|
+
code="agent_loading_interrupt_ignored",
|
|
617
|
+
message="Interrupt ignored while agent infrastructure is loading.",
|
|
618
|
+
display_message=_COORDINATOR_INTERRUPT_IGNORED_LOADING.bind(),
|
|
619
|
+
session_id=self._session.session_id,
|
|
620
|
+
)
|
|
621
|
+
)
|
|
622
|
+
return
|
|
623
|
+
executor = self._current.loaded.bindings if self._current.loaded is not None else None
|
|
624
|
+
interrupt_task = self._turn_state.lease.run_task
|
|
625
|
+
self._trajectory_recorder.interrupt_requested_soon()
|
|
626
|
+
if executor is not None and not executor.state.running:
|
|
627
|
+
self._turn_state.lease.request_pre_executor_interrupt(interrupt_task)
|
|
628
|
+
if self._current.loaded is not None and self._current.loaded.sub_agent_tools is not None:
|
|
629
|
+
await self._current.loaded.sub_agent_tools.cascade_abort_all()
|
|
630
|
+
if executor is not None and interrupt_task is not None and self._turn_state.lease.run_task is interrupt_task:
|
|
631
|
+
if executor.state.running:
|
|
632
|
+
handle = executor.backend.active_handle
|
|
633
|
+
if handle is not None:
|
|
634
|
+
await executor.backend.abort(handle, AbortCause.USER_CANCEL)
|
|
635
|
+
else:
|
|
636
|
+
self._turn_state.lease.request_pre_executor_interrupt(interrupt_task)
|
|
637
|
+
self.schedule_user_interrupt_hook()
|
|
638
|
+
|
|
639
|
+
async def on_user_retry(self, event: UserRetry) -> None:
|
|
640
|
+
"""Handle retry requests and route them to immediate or pending execution."""
|
|
641
|
+
await self._retry().handle_user_retry(event)
|
|
642
|
+
|
|
643
|
+
async def on_user_inject(self, event: UserInject) -> None:
|
|
644
|
+
"""Handle user injection (prompt inserted before next model call)."""
|
|
645
|
+
self._turn_state.begin_inflight_injection(event.injection_id)
|
|
646
|
+
preparation_tracker = PreAdmissionPreparationTracker()
|
|
647
|
+
handed_off = False
|
|
648
|
+
try:
|
|
649
|
+
await self._start_pre_admission_preparation(preparation_tracker)
|
|
650
|
+
await self._wait_for_pre_admission_gate(self._permits.wait_for_agent_load_idle, preparation_tracker)
|
|
651
|
+
preparation = preparation_tracker.preparation
|
|
652
|
+
if self._current.loaded is None:
|
|
653
|
+
if preparation is not None:
|
|
654
|
+
await preparation.finished(outcome=PreparationOutcome.NOT_READY)
|
|
655
|
+
return
|
|
656
|
+
handed_off = await self._injector.inject(
|
|
657
|
+
event.text,
|
|
658
|
+
created_at=event.timestamp,
|
|
659
|
+
route="fsm_active",
|
|
660
|
+
reject_images_without_target=False,
|
|
661
|
+
injection_id=event.injection_id,
|
|
662
|
+
preparation=preparation,
|
|
663
|
+
preparation_tracker=preparation_tracker,
|
|
664
|
+
)
|
|
665
|
+
except asyncio.CancelledError:
|
|
666
|
+
preparation = preparation_tracker.preparation
|
|
667
|
+
if (
|
|
668
|
+
preparation is not None
|
|
669
|
+
and not preparation_tracker.preparation_handed_off
|
|
670
|
+
and not preparation.finished_state
|
|
671
|
+
):
|
|
672
|
+
preparation.finished_soon(outcome=PreparationOutcome.CANCELLED)
|
|
673
|
+
raise
|
|
674
|
+
except BaseException:
|
|
675
|
+
preparation = preparation_tracker.preparation
|
|
676
|
+
if (
|
|
677
|
+
preparation is not None
|
|
678
|
+
and not preparation_tracker.preparation_handed_off
|
|
679
|
+
and not preparation.finished_state
|
|
680
|
+
):
|
|
681
|
+
preparation.finished_soon(outcome=PreparationOutcome.PREPARATION_FAILED)
|
|
682
|
+
raise
|
|
683
|
+
finally:
|
|
684
|
+
self._turn_state.lease.deregister_pre_admission_preparation(preparation_tracker.current)
|
|
685
|
+
self._turn_state.finish_inflight_injection(event.injection_id)
|
|
686
|
+
preparation = preparation_tracker.preparation
|
|
687
|
+
if (
|
|
688
|
+
preparation is not None
|
|
689
|
+
and not handed_off
|
|
690
|
+
and not preparation_tracker.preparation_handed_off
|
|
691
|
+
and not preparation.finished_state
|
|
692
|
+
):
|
|
693
|
+
await preparation.finished(outcome=PreparationOutcome.PREPARATION_FAILED)
|
|
694
|
+
|
|
695
|
+
async def on_user_inject_cancel(self, event: UserInjectCancel) -> None:
|
|
696
|
+
"""Withdraw a queued mid-run injection before the model sees it.
|
|
697
|
+
|
|
698
|
+
Covers both pending phases: an injection already queued on the
|
|
699
|
+
middleware is removed here directly (including its pre-appended
|
|
700
|
+
approval judge context), and an injection still in awaited admission
|
|
701
|
+
aborts via a cancel mark it observes before committing. Everything
|
|
702
|
+
below is synchronous, so the injection cannot move between phases
|
|
703
|
+
mid-cancel. A cancel that matches neither phase is a no-op — the
|
|
704
|
+
injection already resolved (for a consumed one, the ``consumed=True``
|
|
705
|
+
result tells frontends the text reached the model) and recording a
|
|
706
|
+
mark would leave it dangling for the rest of the session.
|
|
707
|
+
"""
|
|
708
|
+
injection_id = event.injection_id
|
|
709
|
+
if not injection_id:
|
|
710
|
+
return
|
|
711
|
+
executor = self._current.loaded.bindings if self._current.loaded is not None else None
|
|
712
|
+
if executor is None:
|
|
713
|
+
if self._turn_state.is_injection_inflight(injection_id):
|
|
714
|
+
self._turn_state.mark_injection_cancelled(injection_id)
|
|
715
|
+
return
|
|
716
|
+
removed = executor.cancel_injection(injection_id)
|
|
717
|
+
if removed is None:
|
|
718
|
+
if self._turn_state.is_injection_inflight(injection_id):
|
|
719
|
+
self._turn_state.mark_injection_cancelled(injection_id)
|
|
720
|
+
return
|
|
721
|
+
executor.approval.remove_user_message(removed.text)
|
|
722
|
+
if removed.preparation is not None:
|
|
723
|
+
removed.preparation.finished_soon(
|
|
724
|
+
outcome=PreparationOutcome.CANCELLED,
|
|
725
|
+
target_turn_id=removed.target_turn_id,
|
|
726
|
+
)
|
|
727
|
+
await self._bus.publish(
|
|
728
|
+
UserInjectResult(
|
|
729
|
+
text=removed.text,
|
|
730
|
+
consumed=False,
|
|
731
|
+
created_at=removed.created_at,
|
|
732
|
+
injection_id=injection_id,
|
|
733
|
+
session_id=self._session.session_id,
|
|
734
|
+
)
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
async def _abandon_cancelled_injection_submit(self, event: UserMessage) -> bool:
|
|
738
|
+
"""Publish an abandoned result and return True for a cancelled locked submit."""
|
|
739
|
+
if not self._turn_state.discard_injection_cancellation(event.injection_id):
|
|
740
|
+
return False
|
|
741
|
+
await self._bus.publish(
|
|
742
|
+
UserInjectResult(
|
|
743
|
+
text=event.text,
|
|
744
|
+
consumed=False,
|
|
745
|
+
created_at=event.timestamp,
|
|
746
|
+
injection_id=event.injection_id,
|
|
747
|
+
session_id=self._session.session_id,
|
|
748
|
+
)
|
|
749
|
+
)
|
|
750
|
+
return True
|
|
751
|
+
|
|
752
|
+
def check_pending_retry(self) -> None:
|
|
753
|
+
"""If a retry was queued while the executor was running, start it now."""
|
|
754
|
+
self._retry().start_pending_retry_if_due()
|
|
755
|
+
|
|
756
|
+
async def prepare_user_contents(
|
|
757
|
+
self,
|
|
758
|
+
text: str,
|
|
759
|
+
*,
|
|
760
|
+
discovered: AttachmentDiscoveryResult | None = None,
|
|
761
|
+
admission: PromptAdmissionScope | None = None,
|
|
762
|
+
event_session_id: str | None = None,
|
|
763
|
+
) -> list[Any] | None:
|
|
764
|
+
"""Return user-message contents or publish a recoverable attachment error."""
|
|
765
|
+
result = await self._content.prepare_fresh(
|
|
766
|
+
text,
|
|
767
|
+
discovered=discovered,
|
|
768
|
+
event_session_id=event_session_id,
|
|
769
|
+
should_publish=self._publication_guard_for_admission(admission),
|
|
770
|
+
)
|
|
771
|
+
return None if result is None else result.contents
|
|
772
|
+
|
|
773
|
+
async def reject_text_only_prepared_contents(
|
|
774
|
+
self,
|
|
775
|
+
text: str,
|
|
776
|
+
contents: list[Any],
|
|
777
|
+
*,
|
|
778
|
+
admission: PromptAdmissionScope,
|
|
779
|
+
event_session_id: str | None,
|
|
780
|
+
) -> bool:
|
|
781
|
+
"""Reject prebuilt image contents before a fresh prompt is promoted."""
|
|
782
|
+
return await self._content.reject_text_only_prepared_contents(
|
|
783
|
+
text,
|
|
784
|
+
contents,
|
|
785
|
+
event_session_id=event_session_id,
|
|
786
|
+
should_publish=self._publication_guard_for_admission(admission),
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
async def _wait_for_existing_run_task(self) -> None:
|
|
790
|
+
"""Wait for current run-task cleanup, if any."""
|
|
791
|
+
task = self._turn_state.lease.run_task
|
|
792
|
+
if task is not None and not task.done():
|
|
793
|
+
await task
|
|
794
|
+
|
|
795
|
+
def _admission_owner_is_current(self, admission: PromptAdmissionScope) -> bool:
|
|
796
|
+
"""Return whether *admission* still belongs to the live session/build owner."""
|
|
797
|
+
return (
|
|
798
|
+
self._permits.session_generation == admission.session_generation
|
|
799
|
+
and self._permits.build_generation == admission.build_generation
|
|
800
|
+
)
|
|
801
|
+
|
|
802
|
+
def _publication_guard_for_admission(
|
|
803
|
+
self,
|
|
804
|
+
admission: PromptAdmissionScope | None,
|
|
805
|
+
) -> Callable[[], bool] | None:
|
|
806
|
+
"""Return a prompt-preparation side-effect guard for an exact admission."""
|
|
807
|
+
if admission is None:
|
|
808
|
+
return None
|
|
809
|
+
return lambda: self._admission_owner_is_current(admission)
|
|
810
|
+
|
|
811
|
+
def _fresh_prompt_fsm_accepts(self) -> bool:
|
|
812
|
+
"""Return whether the current FSM state can start a fresh user turn."""
|
|
813
|
+
return self._fsm.state in (
|
|
814
|
+
EngineState.UNINITIALIZED,
|
|
815
|
+
EngineState.IDLE,
|
|
816
|
+
EngineState.INTERRUPTED,
|
|
817
|
+
EngineState.FAILED,
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
async def _publish_prompt_admission_conflict(self) -> None:
|
|
821
|
+
"""Publish a deterministic conflict when a fresh prompt cannot promote."""
|
|
822
|
+
await self._bus.publish(
|
|
823
|
+
Error(
|
|
824
|
+
code="prompt_admission_conflict",
|
|
825
|
+
message="Prompt could not be admitted because another turn started.",
|
|
826
|
+
display_message=_COORDINATOR_PROMPT_ADMISSION_CONFLICT.bind(),
|
|
827
|
+
session_id=self._session.session_id,
|
|
828
|
+
)
|
|
829
|
+
)
|
|
830
|
+
|
|
831
|
+
async def _evaluate_user_prompt_submit(
|
|
832
|
+
self,
|
|
833
|
+
text: str,
|
|
834
|
+
*,
|
|
835
|
+
injected: bool | None,
|
|
836
|
+
target_operation_id: str | None = None,
|
|
837
|
+
trajectory_context: TrajectoryContext | None = None,
|
|
838
|
+
) -> HookDecision | None:
|
|
839
|
+
"""Run ``user_prompt_submit`` hooks without applying reminder side effects."""
|
|
840
|
+
return await self._gate.evaluate(
|
|
841
|
+
text,
|
|
842
|
+
injected=injected,
|
|
843
|
+
target_operation_id=target_operation_id,
|
|
844
|
+
trajectory_context=trajectory_context,
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
def _open_pre_turn_preparation(self) -> PreparationTrace | None:
|
|
848
|
+
"""Open a session-root preparation scope before prompt admission awaits."""
|
|
849
|
+
context = self._trajectory_recorder.context()
|
|
850
|
+
if context is not None:
|
|
851
|
+
context = context.with_turn(None).with_run(None)
|
|
852
|
+
return PreparationTrace.open(
|
|
853
|
+
scope=PreparationScope.PRE_TURN,
|
|
854
|
+
phase="input_admission",
|
|
855
|
+
context=context,
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
async def _start_pre_admission_preparation(self, tracker: PreAdmissionPreparationTracker) -> None:
|
|
859
|
+
"""Start and register a preparation against the current session context."""
|
|
860
|
+
preparation = self._open_pre_turn_preparation()
|
|
861
|
+
if preparation is None:
|
|
862
|
+
tracker.current = None
|
|
863
|
+
return
|
|
864
|
+
entry = PreAdmissionPreparationEntry(preparation=preparation)
|
|
865
|
+
tracker.current = entry
|
|
866
|
+
await preparation.started()
|
|
867
|
+
self._turn_state.lease.register_pre_admission_preparation(entry)
|
|
868
|
+
|
|
869
|
+
async def _wait_for_pre_admission_gate(
|
|
870
|
+
self,
|
|
871
|
+
wait_for_gate: Callable[[], Awaitable[Any]],
|
|
872
|
+
tracker: PreAdmissionPreparationTracker,
|
|
873
|
+
) -> None:
|
|
874
|
+
"""Wait at one gate and rebind a preparation swept by a session boundary."""
|
|
875
|
+
entry = tracker.current
|
|
876
|
+
preparation = tracker.preparation
|
|
877
|
+
await input_admission_wait(wait_for_gate, preparation, entry)
|
|
878
|
+
if preparation is None or not preparation.finished_state:
|
|
879
|
+
return
|
|
880
|
+
self._turn_state.lease.deregister_pre_admission_preparation(entry)
|
|
881
|
+
await self._start_pre_admission_preparation(tracker)
|
|
882
|
+
|
|
883
|
+
async def _handle_user_prompt_submit_decision(
|
|
884
|
+
self,
|
|
885
|
+
decision: HookDecision | None,
|
|
886
|
+
*,
|
|
887
|
+
injected: bool | None,
|
|
888
|
+
session_id: str | None = None,
|
|
889
|
+
) -> bool:
|
|
890
|
+
"""Return True after publishing when a prompt-submit hook blocked."""
|
|
891
|
+
return await self._gate.handle_decision(
|
|
892
|
+
decision,
|
|
893
|
+
injected=injected,
|
|
894
|
+
session_id=session_id,
|
|
895
|
+
)
|
|
896
|
+
|
|
897
|
+
def _queue_prompt_hook_reminders(
|
|
898
|
+
self,
|
|
899
|
+
decision: HookDecision | None,
|
|
900
|
+
*,
|
|
901
|
+
injected: bool | None,
|
|
902
|
+
) -> None:
|
|
903
|
+
"""Apply non-blocking prompt-submit hook reminders after prompt validation passes."""
|
|
904
|
+
self._gate.queue_reminders(decision, injected=injected)
|
|
905
|
+
|
|
906
|
+
def schedule_user_interrupt_hook(self) -> None:
|
|
907
|
+
"""Schedule the asynchronous user-interrupt lifecycle hook."""
|
|
908
|
+
self._hooks.schedule_user_interrupt()
|
|
909
|
+
|
|
910
|
+
@property
|
|
911
|
+
def conversation_revision(self) -> int:
|
|
912
|
+
"""Monotonic fresh/retry lifecycle revision for stale projections."""
|
|
913
|
+
return self._turn_state.lease.conversation_revision
|
|
914
|
+
|
|
915
|
+
def execution(self) -> ExecutionSnapshot:
|
|
916
|
+
"""What the execution lease is running right now."""
|
|
917
|
+
return self._turn_state.lease.execution()
|
|
918
|
+
|
|
919
|
+
def execution_busy(self) -> bool:
|
|
920
|
+
"""Existing lifecycle busy predicate, including preparation and final save."""
|
|
921
|
+
return self._turn_state.lease.execution_busy()
|
|
922
|
+
|
|
923
|
+
def turn_accepts_injection(self) -> bool:
|
|
924
|
+
"""Existing FSM is_running predicate, including pending retry and child waits."""
|
|
925
|
+
return self._fsm.is_running()
|
|
926
|
+
|
|
927
|
+
@property
|
|
928
|
+
def turn_lifecycle_task(self) -> asyncio.Task[None] | None:
|
|
929
|
+
"""Return the currently owned execution/finalization task.
|
|
930
|
+
|
|
931
|
+
Callers that need a boundary for one captured turn should retain this
|
|
932
|
+
exact task instead of later awaiting the replaceable run-task chain.
|
|
933
|
+
"""
|
|
934
|
+
return self.run_task
|
|
935
|
+
|
|
936
|
+
def was_turn_lifecycle_saved(self, task: asyncio.Task[None]) -> bool:
|
|
937
|
+
"""Return whether *task* completed its final session save successfully."""
|
|
938
|
+
return self.was_run_task_finally_saved(task)
|
|
939
|
+
|
|
940
|
+
async def run_and_save(
|
|
941
|
+
self,
|
|
942
|
+
text: str,
|
|
943
|
+
created_at: datetime | str | None = None,
|
|
944
|
+
contents: list[Any] | None = None,
|
|
945
|
+
*,
|
|
946
|
+
run_scope: CurrentRunScope | None = None,
|
|
947
|
+
injection_window: CurrentRunInjectionWindow | None = None,
|
|
948
|
+
admission_preparation: PreparationTrace | None = None,
|
|
949
|
+
) -> None:
|
|
950
|
+
"""Execute the agent and auto-save the session afterward."""
|
|
951
|
+
task = asyncio.current_task()
|
|
952
|
+
unbind = None
|
|
953
|
+
binding_failure: Exception | None = None
|
|
954
|
+
try:
|
|
955
|
+
if self._current.loaded is not None and task is not None:
|
|
956
|
+
unbind = self._current.loaded.conversation.bind_operation(
|
|
957
|
+
TurnTaskBinding(
|
|
958
|
+
task,
|
|
959
|
+
self._current.loaded.bindings.backend.latch_abort if self._current.loaded is not None else None,
|
|
960
|
+
)
|
|
961
|
+
)
|
|
962
|
+
except Exception as exc:
|
|
963
|
+
# Promotion already owns the Turn. Let its ordinary admission
|
|
964
|
+
# failure path preserve input, finalize, save, and release it.
|
|
965
|
+
binding_failure = exc
|
|
966
|
+
try:
|
|
967
|
+
await self.run_fresh(
|
|
968
|
+
text,
|
|
969
|
+
created_at=created_at,
|
|
970
|
+
contents=contents,
|
|
971
|
+
run_scope=run_scope,
|
|
972
|
+
injection_window=injection_window,
|
|
973
|
+
admission_preparation=admission_preparation,
|
|
974
|
+
binding_failure=binding_failure,
|
|
975
|
+
)
|
|
976
|
+
finally:
|
|
977
|
+
if unbind is not None:
|
|
978
|
+
unbind()
|
|
979
|
+
|
|
980
|
+
async def retry_and_save(
|
|
981
|
+
self,
|
|
982
|
+
additional_text: str = "",
|
|
983
|
+
created_at: datetime | str | None = None,
|
|
984
|
+
*,
|
|
985
|
+
run_scope: CurrentRunScope | None = None,
|
|
986
|
+
injection_window: CurrentRunInjectionWindow | None = None,
|
|
987
|
+
admission_preparation: PreparationTrace | None = None,
|
|
988
|
+
) -> None:
|
|
989
|
+
"""Resume the agent from current state and auto-save afterward.
|
|
990
|
+
|
|
991
|
+
When *additional_text* is non-empty, the executor uses it as the
|
|
992
|
+
mid-turn continuation prompt (instead of the placeholder
|
|
993
|
+
``"continue"``) and preserves it in history as a real user turn.
|
|
994
|
+
"""
|
|
995
|
+
task = asyncio.current_task()
|
|
996
|
+
unbind = None
|
|
997
|
+
binding_failure: Exception | None = None
|
|
998
|
+
try:
|
|
999
|
+
if self._current.loaded is not None and task is not None:
|
|
1000
|
+
unbind = self._current.loaded.conversation.bind_operation(
|
|
1001
|
+
TurnTaskBinding(
|
|
1002
|
+
task,
|
|
1003
|
+
self._current.loaded.bindings.backend.latch_abort if self._current.loaded is not None else None,
|
|
1004
|
+
)
|
|
1005
|
+
)
|
|
1006
|
+
except Exception as exc:
|
|
1007
|
+
# Promotion already owns the Turn. Let its ordinary admission
|
|
1008
|
+
# failure path preserve input, finalize, save, and release it.
|
|
1009
|
+
binding_failure = exc
|
|
1010
|
+
try:
|
|
1011
|
+
await self.run_retry(
|
|
1012
|
+
additional_text,
|
|
1013
|
+
created_at=created_at,
|
|
1014
|
+
run_scope=run_scope,
|
|
1015
|
+
injection_window=injection_window,
|
|
1016
|
+
admission_preparation=admission_preparation,
|
|
1017
|
+
binding_failure=binding_failure,
|
|
1018
|
+
)
|
|
1019
|
+
finally:
|
|
1020
|
+
if unbind is not None:
|
|
1021
|
+
unbind()
|
|
1022
|
+
|
|
1023
|
+
async def on_sub_agent_retry(self, event: InvocationRetryRequested) -> None:
|
|
1024
|
+
"""Route a user's per-card Retry click to the owning controller."""
|
|
1025
|
+
await sub_agent_coordination.on_sub_agent_retry(self._current, event)
|
|
1026
|
+
|
|
1027
|
+
async def on_sub_agent_abort(self, event: InvocationAbortRequested) -> None:
|
|
1028
|
+
"""Route a user's per-card Abort click to the owning controller."""
|
|
1029
|
+
await sub_agent_coordination.on_sub_agent_abort(self._current, event)
|
|
1030
|
+
|
|
1031
|
+
async def on_sub_agent_paused(self, event: InvocationPaused) -> None:
|
|
1032
|
+
"""Track a newly paused sub-agent and drive FSM / marker.
|
|
1033
|
+
|
|
1034
|
+
Idempotent on the paused set — if the same id arrives twice
|
|
1035
|
+
(controller re-publishes after retry exhaustion, for example)
|
|
1036
|
+
the FSM transition only fires on the 0→1 edge.
|
|
1037
|
+
|
|
1038
|
+
Defensive FSM guard: if the parent run has already terminated
|
|
1039
|
+
(e.g. the bus is dispatching a stale pause event that was queued
|
|
1040
|
+
before the parent's task was cancelled and ``_post_run`` ran),
|
|
1041
|
+
drop the event silently rather than re-inserting a marker on top
|
|
1042
|
+
of an already-terminal ``interrupted``/``error`` marker. The
|
|
1043
|
+
parent invariant ("parent run ends only after all sub-agents
|
|
1044
|
+
resolve") should make this unreachable, but defense in depth
|
|
1045
|
+
keeps history well-formed if that invariant ever breaks.
|
|
1046
|
+
"""
|
|
1047
|
+
await sub_agent_coordination.on_sub_agent_paused(
|
|
1048
|
+
self._turn_state, self._history, self._fsm, self._trajectory_recorder, event
|
|
1049
|
+
)
|
|
1050
|
+
|
|
1051
|
+
async def on_sub_agent_unpaused(
|
|
1052
|
+
self,
|
|
1053
|
+
event: InvocationResumed | InvocationAborted | InvocationCascadeAborted,
|
|
1054
|
+
) -> None:
|
|
1055
|
+
"""Common handler — retry/abort/cascade all remove the invocation from the paused set.
|
|
1056
|
+
|
|
1057
|
+
FSM transitions only on the N→0 edge (last paused sub-agent
|
|
1058
|
+
resolved). Marker is updated or stripped accordingly.
|
|
1059
|
+
"""
|
|
1060
|
+
await sub_agent_coordination.on_sub_agent_unpaused(
|
|
1061
|
+
self._turn_state, self._history, self._fsm, self._trajectory_recorder, event
|
|
1062
|
+
)
|