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,771 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Workflow run admission and routing for one engine.
|
|
4
|
+
|
|
5
|
+
A ``WorkflowRunRequest`` is answered exactly once, with ``WorkflowRunAccepted``
|
|
6
|
+
or ``WorkflowRunRejected``; a repeated ``request_id`` gets the same answer
|
|
7
|
+
again and starts nothing. Admission reserves the execution lease first (one
|
|
8
|
+
workflow run globally, never beside a live turn), then resolves the file,
|
|
9
|
+
checks its confirmed bytes before probing its interpreter, checks the prepared
|
|
10
|
+
environment, loads it on a fresh worker, checks the caller's expected digests
|
|
11
|
+
and the full confirmation record, admits the manifest against
|
|
12
|
+
the registries, and opens the run record. Only then is the request accepted
|
|
13
|
+
and the runner started. Every rejection along the way releases the lease
|
|
14
|
+
and closes the worker.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import asyncio
|
|
20
|
+
import logging
|
|
21
|
+
import shutil
|
|
22
|
+
from collections import OrderedDict
|
|
23
|
+
from collections.abc import AsyncIterator, Callable
|
|
24
|
+
from contextlib import asynccontextmanager
|
|
25
|
+
from dataclasses import asdict, dataclass, replace
|
|
26
|
+
from datetime import UTC, datetime
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import TYPE_CHECKING, Any, Final
|
|
29
|
+
|
|
30
|
+
from chrys.foundation.config.settings import Settings
|
|
31
|
+
from chrys.foundation.config.warnings import settings_warning_events
|
|
32
|
+
from chrys.foundation.events.types import (
|
|
33
|
+
SessionDeleted,
|
|
34
|
+
WorkflowCancelRequest,
|
|
35
|
+
WorkflowModelChangeRequest,
|
|
36
|
+
WorkflowModelChangeResult,
|
|
37
|
+
WorkflowNodeAnswer,
|
|
38
|
+
WorkflowNodeRetryRequest,
|
|
39
|
+
WorkflowRollbackRequest,
|
|
40
|
+
WorkflowRollbackResult,
|
|
41
|
+
WorkflowRunAccepted,
|
|
42
|
+
WorkflowRunRejected,
|
|
43
|
+
WorkflowRunRequest,
|
|
44
|
+
)
|
|
45
|
+
from chrys.foundation.models.workflow_session import WorkflowSessionSelection
|
|
46
|
+
from chrys.foundation.platform import get_platform
|
|
47
|
+
from chrys.foundation.platform.files import surrogate_safe_text
|
|
48
|
+
from chrys.foundation.trajectory.ids import new_analytics_id
|
|
49
|
+
from chrys.foundation.util.once_close import finish_close
|
|
50
|
+
from chrys.orchestration.engine.execution import WorkflowExecution
|
|
51
|
+
from chrys.orchestration.workflows.agent_node_build import AgentNodeResources
|
|
52
|
+
from chrys.orchestration.workflows.hooks import WorkflowSessionHooks
|
|
53
|
+
from chrys.orchestration.workflows.preview import (
|
|
54
|
+
REJECT_NOT_CONFIRMED,
|
|
55
|
+
REJECT_SPEC_CHANGED,
|
|
56
|
+
WorkflowPreviewError,
|
|
57
|
+
ledger_entry_for,
|
|
58
|
+
load_workflow,
|
|
59
|
+
materialize_runtime_sdk,
|
|
60
|
+
prepare_workflow_environment,
|
|
61
|
+
worker_bytecode_cache_dir,
|
|
62
|
+
)
|
|
63
|
+
from chrys.orchestration.workflows.runner import WorkerCallbacks, WorkflowRunner, WorkflowRunResult
|
|
64
|
+
from chrys.orchestration.workflows.session import (
|
|
65
|
+
WorkflowSessionInUse,
|
|
66
|
+
WorkflowSessionNotFound,
|
|
67
|
+
WorkflowSessionOwner,
|
|
68
|
+
WorkflowWorkspaceLocked,
|
|
69
|
+
)
|
|
70
|
+
from chrys.orchestration.workflows.settings import admission_settings, load_workflow_settings
|
|
71
|
+
from chrys.service.approval.policy import ApprovalMode
|
|
72
|
+
from chrys.service.hooks.events import HookEvent
|
|
73
|
+
from chrys.service.profiles.agents.registry import AgentProfileRegistry
|
|
74
|
+
from chrys.service.trajectory.workflow import WorkflowTrace
|
|
75
|
+
from chrys.service.workflows.admission import AdmissionError, admit_manifest
|
|
76
|
+
from chrys.service.workflows.discovery import SOURCE_KIND_BUILTIN, WorkflowSource, discover_workflows
|
|
77
|
+
from chrys.service.workflows.journal import WorkflowJournal
|
|
78
|
+
from chrys.service.workflows.layout import run_dir
|
|
79
|
+
from chrys.service.workflows.ledger import ConfirmationLedger, ledger_path
|
|
80
|
+
from chrys.service.workflows.model_selection import resolve_workflow_model
|
|
81
|
+
from chrys.service.workflows.outcomes import REASON_DEADLINE_EXCEEDED, REASON_SHUTDOWN
|
|
82
|
+
from chrys.service.workflows.scheduler import RunMode
|
|
83
|
+
from chrys.service.workflows.store import RunHeader, RunSpec, WorkflowRunStore, WorkflowStorageFailed
|
|
84
|
+
|
|
85
|
+
if TYPE_CHECKING:
|
|
86
|
+
from chrys.foundation.config.settings_store import SettingsHandle
|
|
87
|
+
from chrys.foundation.events.bus import EventBus
|
|
88
|
+
from chrys.orchestration.engine.run.turn_state import TurnRuntimeState
|
|
89
|
+
from chrys.orchestration.engine.state.active_session import ActiveSession
|
|
90
|
+
from chrys.orchestration.workflows.session import HookFactory
|
|
91
|
+
from chrys.service.mcp.cache import MCPConnectionCache
|
|
92
|
+
from chrys.service.profiles.models.registry import ModelProfileRegistry
|
|
93
|
+
from chrys.service.session.persistence import SessionPersistence
|
|
94
|
+
from chrys.service.workflows.ledger import LedgerEntry
|
|
95
|
+
|
|
96
|
+
logger = logging.getLogger(__name__)
|
|
97
|
+
|
|
98
|
+
REJECT_INVALID_REQUEST: Final = "invalid_request"
|
|
99
|
+
REJECT_SESSION_CHANGED: Final = "session_changed"
|
|
100
|
+
REJECT_SESSION_NOT_FOUND: Final = "session_not_found"
|
|
101
|
+
REJECT_SESSION_IN_USE: Final = "session_in_use"
|
|
102
|
+
REJECT_ENGINE_NOT_READY: Final = "engine_not_ready"
|
|
103
|
+
REJECT_SHUTTING_DOWN: Final = "shutting_down"
|
|
104
|
+
REJECT_CANCELLED: Final = "cancelled"
|
|
105
|
+
REJECT_WORKFLOW_ACTIVE: Final = "workflow_active"
|
|
106
|
+
REJECT_TURN_ACTIVE: Final = "turn_active"
|
|
107
|
+
REJECT_ENGINE_BUSY: Final = "engine_busy"
|
|
108
|
+
REJECT_WORKFLOW_NOT_FOUND: Final = "workflow_not_found"
|
|
109
|
+
REJECT_ENVIRONMENT_CHANGED: Final = "environment_changed"
|
|
110
|
+
REJECT_STORAGE_FAILED: Final = "storage_failed"
|
|
111
|
+
REJECT_INTERNAL_ERROR: Final = "internal_error"
|
|
112
|
+
REJECT_WORKSPACE_LOCKED: Final = "workspace_locked"
|
|
113
|
+
REJECT_WORKING_DIR_MISSING: Final = "working_dir_missing"
|
|
114
|
+
|
|
115
|
+
MAX_REMEMBERED_REPLIES: Final = 256
|
|
116
|
+
MAX_REMEMBERED_RESULTS: Final = 16
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class _Rejection(Exception):
|
|
120
|
+
def __init__(self, code: str, message: str) -> None:
|
|
121
|
+
super().__init__(message)
|
|
122
|
+
self.code = code
|
|
123
|
+
self.message = message
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _not_confirmed(source: WorkflowSource) -> _Rejection:
|
|
127
|
+
return _Rejection(
|
|
128
|
+
REJECT_NOT_CONFIRMED,
|
|
129
|
+
f"Workflow {source.workflow_id!r} at {source.canonical_path} is not confirmed for this environment; "
|
|
130
|
+
"review and confirm it first.",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@dataclass(slots=True)
|
|
135
|
+
class _ActiveRun:
|
|
136
|
+
execution: WorkflowExecution
|
|
137
|
+
session_id: str = ""
|
|
138
|
+
owner: WorkflowSessionOwner | None = None
|
|
139
|
+
source: WorkflowSource | None = None
|
|
140
|
+
runner: WorkflowRunner | None = None
|
|
141
|
+
cancel_reason: str | None = None
|
|
142
|
+
"""The first admission cancellation cause; also guards against cancelling its cleanup twice."""
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class WorkflowCoordinator:
|
|
146
|
+
"""Owns workflow event subscriptions, the one active run, and the request → reply memory."""
|
|
147
|
+
|
|
148
|
+
def __init__(
|
|
149
|
+
self,
|
|
150
|
+
*,
|
|
151
|
+
bus: EventBus,
|
|
152
|
+
session: ActiveSession,
|
|
153
|
+
persistence: SessionPersistence,
|
|
154
|
+
build_hooks: HookFactory,
|
|
155
|
+
turn_state: TurnRuntimeState,
|
|
156
|
+
settings_handle: SettingsHandle,
|
|
157
|
+
agent_registry: AgentProfileRegistry | None,
|
|
158
|
+
model_registry: ModelProfileRegistry | None,
|
|
159
|
+
allow_user_interaction: bool,
|
|
160
|
+
mcp_cache: MCPConnectionCache,
|
|
161
|
+
config_dir: Callable[[], Path] | None = None,
|
|
162
|
+
) -> None:
|
|
163
|
+
self._mcp_cache = mcp_cache
|
|
164
|
+
self._bus = bus
|
|
165
|
+
self._session = session
|
|
166
|
+
self._persistence = persistence
|
|
167
|
+
self._build_hooks = build_hooks
|
|
168
|
+
self._turn_state = turn_state
|
|
169
|
+
self._settings_handle = settings_handle
|
|
170
|
+
self._startup_settings = settings_handle.loaded
|
|
171
|
+
self._agent_registry = agent_registry
|
|
172
|
+
self._model_registry = model_registry
|
|
173
|
+
self._mode = RunMode.INTERACTIVE if allow_user_interaction else RunMode.HEADLESS
|
|
174
|
+
self._allow_user_interaction = allow_user_interaction
|
|
175
|
+
self._config_dir: Callable[[], Path] = config_dir or (lambda: get_platform().config_dir)
|
|
176
|
+
self._replies: OrderedDict[str, WorkflowRunAccepted | WorkflowRunRejected] = OrderedDict()
|
|
177
|
+
self._rollback_replies: OrderedDict[str, WorkflowRollbackResult] = OrderedDict()
|
|
178
|
+
self._results: OrderedDict[str, WorkflowRunResult] = OrderedDict()
|
|
179
|
+
self._model_changes: set[str] = set()
|
|
180
|
+
self._active: _ActiveRun | None = None
|
|
181
|
+
self._hooks = WorkflowSessionHooks()
|
|
182
|
+
self._closing = False
|
|
183
|
+
|
|
184
|
+
# -- observation ---------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def active_run_id(self) -> str | None:
|
|
188
|
+
return self._active.execution.run_id if self._active is not None else None
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def active_request_id(self) -> str | None:
|
|
192
|
+
"""The request the active run (admitted or still being admitted) answers to."""
|
|
193
|
+
return self._active.execution.request_id if self._active is not None else None
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def active_source(self) -> WorkflowSource | None:
|
|
197
|
+
"""The reserved run's source, available from discovery through lease release."""
|
|
198
|
+
return self._active.source if self._active is not None else None
|
|
199
|
+
|
|
200
|
+
def result(self, run_id: str) -> WorkflowRunResult | None:
|
|
201
|
+
"""The full result of a recent run (outputs carry whole values, unlike the event summaries)."""
|
|
202
|
+
return self._results.get(run_id)
|
|
203
|
+
|
|
204
|
+
def mutation_snapshot(self, session_id: str) -> dict[str, Any] | None:
|
|
205
|
+
"""Capture the selected active session's ledger before a deferred frontend read."""
|
|
206
|
+
active = self._active
|
|
207
|
+
owner = active.owner if active is not None else None
|
|
208
|
+
if owner is None or owner.session.session_id != session_id:
|
|
209
|
+
return None
|
|
210
|
+
tracker = owner.session.mutation_tracker
|
|
211
|
+
return tracker.serialize() if tracker is not None else None
|
|
212
|
+
|
|
213
|
+
def set_approval_mode(self, mode: ApprovalMode) -> None:
|
|
214
|
+
"""Synchronize live nodes with the engine's launch policy without session I/O."""
|
|
215
|
+
active = self._active
|
|
216
|
+
if active is not None and active.runner is not None:
|
|
217
|
+
active.runner.set_approval_mode(mode)
|
|
218
|
+
|
|
219
|
+
@asynccontextmanager
|
|
220
|
+
async def _session_owner(
|
|
221
|
+
self, session_id: str, *, allow_active: bool = True
|
|
222
|
+
) -> AsyncIterator[WorkflowSessionOwner]:
|
|
223
|
+
"""Borrow an editable active owner or restore one, keeping close behind the operation."""
|
|
224
|
+
active = self._active
|
|
225
|
+
if active is not None and active.session_id == session_id:
|
|
226
|
+
if not allow_active:
|
|
227
|
+
raise ValueError(
|
|
228
|
+
"This workflow session has an active run. Wait for it to finish before changing its model."
|
|
229
|
+
)
|
|
230
|
+
owner = active.owner
|
|
231
|
+
if owner is not None:
|
|
232
|
+
async with owner.edit() as available:
|
|
233
|
+
if available:
|
|
234
|
+
yield owner
|
|
235
|
+
return
|
|
236
|
+
owner = WorkflowSessionOwner(
|
|
237
|
+
bus=self._bus,
|
|
238
|
+
persistence=self._persistence,
|
|
239
|
+
session_id=session_id,
|
|
240
|
+
workspace=None,
|
|
241
|
+
)
|
|
242
|
+
try:
|
|
243
|
+
await owner.open()
|
|
244
|
+
async with owner.edit() as available:
|
|
245
|
+
if not available:
|
|
246
|
+
raise RuntimeError("The workflow session closed before it could be edited.")
|
|
247
|
+
yield owner
|
|
248
|
+
finally:
|
|
249
|
+
await finish_close(asyncio.create_task(owner.close()))
|
|
250
|
+
|
|
251
|
+
async def on_model_change(self, event: WorkflowModelChangeRequest) -> None:
|
|
252
|
+
result = WorkflowModelChangeResult(session_id=event.session_id, request_id=event.request_id)
|
|
253
|
+
if event.session_id in self._model_changes:
|
|
254
|
+
result.error = "This workflow session's model is being updated. Try again in a moment."
|
|
255
|
+
else:
|
|
256
|
+
# Fence only this session before awaiting its guard. Other sessions
|
|
257
|
+
# can keep executing while this checkpoint is written.
|
|
258
|
+
self._model_changes.add(event.session_id)
|
|
259
|
+
try:
|
|
260
|
+
model = resolve_workflow_model(self._model_registry, event.profile_id)
|
|
261
|
+
if model is None:
|
|
262
|
+
raise ValueError("Select a model profile.")
|
|
263
|
+
async with self._session_owner(event.session_id, allow_active=False) as owner:
|
|
264
|
+
await owner.set_model(model)
|
|
265
|
+
result.selection = owner.selection
|
|
266
|
+
except (ValueError, OSError) as exc:
|
|
267
|
+
result.error = str(exc)
|
|
268
|
+
finally:
|
|
269
|
+
self._model_changes.remove(event.session_id)
|
|
270
|
+
await self._bus.publish(result)
|
|
271
|
+
|
|
272
|
+
async def on_rollback(self, event: WorkflowRollbackRequest) -> None:
|
|
273
|
+
from chrys.orchestration.workflows.rollback import rollback_files
|
|
274
|
+
|
|
275
|
+
prior = self._rollback_replies.get(event.request_id)
|
|
276
|
+
if prior is not None:
|
|
277
|
+
await self._bus.publish(prior)
|
|
278
|
+
return
|
|
279
|
+
result = WorkflowRollbackResult(session_id=event.session_id, request_id=event.request_id, run_id=event.run_id)
|
|
280
|
+
refusal = self._refusal()
|
|
281
|
+
if refusal is not None:
|
|
282
|
+
result.error = refusal[1]
|
|
283
|
+
else:
|
|
284
|
+
with self._turn_state.lease.session_operation():
|
|
285
|
+
try:
|
|
286
|
+
async with self._session_owner(event.session_id) as owner:
|
|
287
|
+
settings = await self._load_run_settings(
|
|
288
|
+
Path(owner.require_workspace().primary_cwd), request_id=event.request_id
|
|
289
|
+
)
|
|
290
|
+
result = await rollback_files(owner, event, settings=settings)
|
|
291
|
+
except (KeyError, ValueError, OSError) as exc:
|
|
292
|
+
result.error = str(exc)
|
|
293
|
+
_remember(self._rollback_replies, event.request_id, result, MAX_REMEMBERED_REPLIES)
|
|
294
|
+
await self._bus.publish(result)
|
|
295
|
+
|
|
296
|
+
# -- wiring -------------------------------------------------------------------------
|
|
297
|
+
|
|
298
|
+
async def subscribe(self) -> None:
|
|
299
|
+
await self._bus.subscribe(WorkflowRollbackRequest, self.on_rollback)
|
|
300
|
+
await self._bus.subscribe(WorkflowRunRequest, self.on_run_request)
|
|
301
|
+
await self._bus.subscribe(WorkflowModelChangeRequest, self.on_model_change)
|
|
302
|
+
await self._bus.subscribe(SessionDeleted, self._on_session_deleted)
|
|
303
|
+
await self._bus.subscribe(WorkflowCancelRequest, self.on_cancel)
|
|
304
|
+
await self._bus.subscribe(WorkflowNodeAnswer, self.on_answer)
|
|
305
|
+
await self._bus.subscribe(WorkflowNodeRetryRequest, self.on_retry)
|
|
306
|
+
|
|
307
|
+
async def shutdown(self) -> None:
|
|
308
|
+
self._closing = True
|
|
309
|
+
await self.abandon_active()
|
|
310
|
+
# Reentrant shutdown from a run subscriber returns before that run
|
|
311
|
+
# drains. Its finally owns session-end, after run-end, in that case.
|
|
312
|
+
if self._active is None:
|
|
313
|
+
await self._hooks.close()
|
|
314
|
+
await self._turn_state.lease.settle_notifications()
|
|
315
|
+
|
|
316
|
+
async def _on_session_deleted(self, event: SessionDeleted) -> None:
|
|
317
|
+
if event.session_id:
|
|
318
|
+
await self._hooks.release(event.session_id)
|
|
319
|
+
|
|
320
|
+
async def abandon_active(self) -> None:
|
|
321
|
+
"""Cancel the active run as a shutdown (its owner left) and wait for its worker to exit.
|
|
322
|
+
|
|
323
|
+
From inside the admission task (a subscriber to the request's reply awaiting a shutdown), the task is
|
|
324
|
+
not cancelled under its own reply: the reply goes out, and a run it admitted starts cancelled.
|
|
325
|
+
"""
|
|
326
|
+
self.cancel_active(reason=REASON_SHUTDOWN)
|
|
327
|
+
await self.wait_idle()
|
|
328
|
+
|
|
329
|
+
def cancel_active(self, *, reason: str = "") -> bool:
|
|
330
|
+
"""Request cancellation with its cause; return whether this request initiated it."""
|
|
331
|
+
active = self._active
|
|
332
|
+
if active is None:
|
|
333
|
+
return False
|
|
334
|
+
if active.runner is not None:
|
|
335
|
+
return active.runner.cancel(reason=reason) is not None
|
|
336
|
+
return self._cancel_admission(active, reason=reason)
|
|
337
|
+
|
|
338
|
+
def _cancel_admission(self, active: _ActiveRun, *, reason: str) -> bool:
|
|
339
|
+
"""Interrupt admission once, preserving cleanup and any reply already being published."""
|
|
340
|
+
if active.cancel_reason is not None or active.execution.request_id in self._replies:
|
|
341
|
+
return False
|
|
342
|
+
active.cancel_reason = reason
|
|
343
|
+
task = active.execution.task
|
|
344
|
+
if task is not None and task is not asyncio.current_task():
|
|
345
|
+
task.cancel()
|
|
346
|
+
return True
|
|
347
|
+
|
|
348
|
+
async def wait_idle(self) -> None:
|
|
349
|
+
"""Wait until the active run, if any, has released the execution lease.
|
|
350
|
+
|
|
351
|
+
Called from inside that run (a subscriber to one of its events awaiting a shutdown, on the run task,
|
|
352
|
+
on the admission task publishing its reply, or on a node task publishing under the runner's lock),
|
|
353
|
+
it returns at once: a run cannot be waited out from within itself, and the cancel already queued
|
|
354
|
+
ends it as soon as the handler returns.
|
|
355
|
+
"""
|
|
356
|
+
active = self._active
|
|
357
|
+
if active is None:
|
|
358
|
+
return
|
|
359
|
+
task = active.execution.task
|
|
360
|
+
if task is None:
|
|
361
|
+
return
|
|
362
|
+
current = asyncio.current_task()
|
|
363
|
+
if task is current or (active.runner is not None and active.runner.holds(current)):
|
|
364
|
+
return
|
|
365
|
+
await asyncio.wait({task})
|
|
366
|
+
|
|
367
|
+
# -- handlers --------------------------------------------------------------------------
|
|
368
|
+
|
|
369
|
+
async def on_run_request(self, event: WorkflowRunRequest) -> None:
|
|
370
|
+
request_id = event.request_id
|
|
371
|
+
if not request_id:
|
|
372
|
+
await self._bus.publish(
|
|
373
|
+
WorkflowRunRejected(
|
|
374
|
+
request_id="",
|
|
375
|
+
error=REJECT_INVALID_REQUEST,
|
|
376
|
+
message="A workflow run request needs a request_id.",
|
|
377
|
+
session_id=event.session_id or None,
|
|
378
|
+
)
|
|
379
|
+
)
|
|
380
|
+
return
|
|
381
|
+
remembered = self._replies.get(request_id)
|
|
382
|
+
if remembered is not None:
|
|
383
|
+
await self._bus.publish(remembered)
|
|
384
|
+
return
|
|
385
|
+
if self._active is not None and self._active.execution.request_id == request_id:
|
|
386
|
+
return # the admission in flight answers this request once, when it is decided
|
|
387
|
+
refusal = self._refusal()
|
|
388
|
+
if refusal is None and event.session_id in self._model_changes:
|
|
389
|
+
refusal = REJECT_SESSION_CHANGED, "This workflow session's model is being updated. Try again in a moment."
|
|
390
|
+
if refusal is not None:
|
|
391
|
+
await self._reply(
|
|
392
|
+
WorkflowRunRejected(
|
|
393
|
+
session_id=event.session_id, request_id=request_id, error=refusal[0], message=refusal[1]
|
|
394
|
+
)
|
|
395
|
+
)
|
|
396
|
+
return
|
|
397
|
+
execution = self._turn_state.lease.begin_workflow(new_analytics_id(), request_id)
|
|
398
|
+
active = _ActiveRun(execution, session_id=event.session_id or "")
|
|
399
|
+
self._active = active
|
|
400
|
+
# Eager start: the run task enters its try/finally before this handler returns, so a shutdown
|
|
401
|
+
# that lands right behind the request releases the lease through the task, never around it.
|
|
402
|
+
execution.task = asyncio.create_task(
|
|
403
|
+
self._run(event, active), name=f"chrys.workflow.run.{execution.run_id}", eager_start=True
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
async def on_cancel(self, event: WorkflowCancelRequest) -> None:
|
|
407
|
+
active = self._active
|
|
408
|
+
if active is None or event.run_id != active.execution.run_id:
|
|
409
|
+
return
|
|
410
|
+
self.cancel_active()
|
|
411
|
+
|
|
412
|
+
async def on_answer(self, event: WorkflowNodeAnswer) -> None:
|
|
413
|
+
active = self._active
|
|
414
|
+
if active is None or active.runner is None or event.run_id != active.execution.run_id:
|
|
415
|
+
return
|
|
416
|
+
if not active.runner.answer(event.node_id, event.activation_id, event.request_id, event.answers):
|
|
417
|
+
logger.info("workflow run %s: no open ask accepts answer %s", event.run_id, event.request_id)
|
|
418
|
+
|
|
419
|
+
async def on_retry(self, event: WorkflowNodeRetryRequest) -> None:
|
|
420
|
+
active = self._active
|
|
421
|
+
if active is None or active.runner is None or event.run_id != active.execution.run_id:
|
|
422
|
+
return
|
|
423
|
+
active.runner.retry(event.node_id, event.activation_id, event.request_id, event.expected_failed_attempt)
|
|
424
|
+
|
|
425
|
+
# -- admission ------------------------------------------------------------------------------
|
|
426
|
+
|
|
427
|
+
def _refusal(self) -> tuple[str, str] | None:
|
|
428
|
+
"""The deterministic reasons a request is refused before anything is reserved."""
|
|
429
|
+
lease = self._turn_state.lease
|
|
430
|
+
if self._persistence.state_store is None:
|
|
431
|
+
return REJECT_ENGINE_NOT_READY, "Workflow execution requires a session store."
|
|
432
|
+
if self._session.shutting_down:
|
|
433
|
+
return REJECT_SHUTTING_DOWN, "The engine is shutting down."
|
|
434
|
+
reason = lease.workflow_start_refusal()
|
|
435
|
+
if reason is None:
|
|
436
|
+
return None
|
|
437
|
+
return reason, {
|
|
438
|
+
REJECT_WORKFLOW_ACTIVE: "A workflow run is already active. Cancel it first.",
|
|
439
|
+
REJECT_TURN_ACTIVE: "A turn is active. Wait for it to finish or interrupt it first.",
|
|
440
|
+
REJECT_ENGINE_BUSY: "The session is being rebuilt, restored or replaced. Try again in a moment.",
|
|
441
|
+
}[reason]
|
|
442
|
+
|
|
443
|
+
async def _run(self, event: WorkflowRunRequest, active: _ActiveRun) -> None:
|
|
444
|
+
execution = active.execution
|
|
445
|
+
session_id = self._session.session_id
|
|
446
|
+
try:
|
|
447
|
+
try:
|
|
448
|
+
runner, journal = await self._admit(event, active)
|
|
449
|
+
except _Rejection as exc:
|
|
450
|
+
await self._reply(
|
|
451
|
+
WorkflowRunRejected(
|
|
452
|
+
session_id=event.session_id, request_id=event.request_id, error=exc.code, message=exc.message
|
|
453
|
+
)
|
|
454
|
+
)
|
|
455
|
+
return
|
|
456
|
+
except asyncio.CancelledError:
|
|
457
|
+
# Cancellation is latched once, so cleanup and this reply cannot be cancelled again by a
|
|
458
|
+
# repeated request. Publish on this task: a subscriber awaiting shutdown must not wait on us.
|
|
459
|
+
if event.request_id not in self._replies:
|
|
460
|
+
cancelled = active.cancel_reason in ("", REASON_DEADLINE_EXCEEDED)
|
|
461
|
+
await self._reply(
|
|
462
|
+
WorkflowRunRejected(
|
|
463
|
+
session_id=event.session_id,
|
|
464
|
+
request_id=event.request_id,
|
|
465
|
+
error=REJECT_CANCELLED if cancelled else REJECT_SHUTTING_DOWN,
|
|
466
|
+
message="The run was cancelled before it was admitted."
|
|
467
|
+
if cancelled
|
|
468
|
+
else "The run was given up before it was admitted.",
|
|
469
|
+
)
|
|
470
|
+
)
|
|
471
|
+
raise
|
|
472
|
+
except Exception as exc:
|
|
473
|
+
# Admission must answer even when it is the one that is broken, or the requester waits forever.
|
|
474
|
+
logger.exception("workflow run %s: admission failed", execution.run_id)
|
|
475
|
+
await self._reply(
|
|
476
|
+
WorkflowRunRejected(
|
|
477
|
+
session_id=event.session_id,
|
|
478
|
+
request_id=event.request_id,
|
|
479
|
+
error=REJECT_INTERNAL_ERROR,
|
|
480
|
+
message=f"{type(exc).__name__}: {exc}",
|
|
481
|
+
)
|
|
482
|
+
)
|
|
483
|
+
return
|
|
484
|
+
if active.owner is None:
|
|
485
|
+
raise RuntimeError("The active workflow has no session owner.")
|
|
486
|
+
active.runner = runner
|
|
487
|
+
if active.cancel_reason is not None:
|
|
488
|
+
cancelled = runner.cancel(reason=active.cancel_reason)
|
|
489
|
+
if cancelled is None:
|
|
490
|
+
raise RuntimeError("Cancelling a fresh workflow runner did not return a drain task.")
|
|
491
|
+
await cancelled # applied before the start: the run begins cancelled and no node executes
|
|
492
|
+
if active.owner.selection is None:
|
|
493
|
+
raise RuntimeError("Accepting a workflow run requires a session selection.")
|
|
494
|
+
await self._reply(
|
|
495
|
+
WorkflowRunAccepted(
|
|
496
|
+
request_id=event.request_id,
|
|
497
|
+
run_id=execution.run_id,
|
|
498
|
+
selection=active.owner.selection,
|
|
499
|
+
)
|
|
500
|
+
)
|
|
501
|
+
workflow_session_id = active.owner.require_session_id()
|
|
502
|
+
|
|
503
|
+
async def attach_session() -> None:
|
|
504
|
+
if active.owner is None:
|
|
505
|
+
raise RuntimeError("The active workflow has no session owner.")
|
|
506
|
+
await self._hooks.attach(active.owner)
|
|
507
|
+
|
|
508
|
+
async def start_hooks() -> None:
|
|
509
|
+
await self._hooks.run_event(
|
|
510
|
+
workflow_session_id,
|
|
511
|
+
HookEvent.WORKFLOW_RUN_START,
|
|
512
|
+
run_id=execution.run_id,
|
|
513
|
+
input_text=event.input_text,
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
async def end_hooks(result: WorkflowRunResult) -> None:
|
|
517
|
+
await self._hooks.run_event(
|
|
518
|
+
workflow_session_id,
|
|
519
|
+
HookEvent.WORKFLOW_RUN_END,
|
|
520
|
+
run_id=result.run_id,
|
|
521
|
+
outcome=result.outcome.value,
|
|
522
|
+
reason=result.reason,
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
try:
|
|
526
|
+
result = await runner.run(
|
|
527
|
+
event.input_text,
|
|
528
|
+
startup=(attach_session, start_hooks),
|
|
529
|
+
record_end=end_hooks,
|
|
530
|
+
)
|
|
531
|
+
finally:
|
|
532
|
+
await journal.store.close()
|
|
533
|
+
_remember(self._results, result.run_id, result, MAX_REMEMBERED_RESULTS)
|
|
534
|
+
except asyncio.CancelledError:
|
|
535
|
+
raise
|
|
536
|
+
except Exception:
|
|
537
|
+
logger.exception("workflow run %s failed outside the runner", execution.run_id)
|
|
538
|
+
finally:
|
|
539
|
+
try:
|
|
540
|
+
if active.owner is not None:
|
|
541
|
+
await active.owner.close()
|
|
542
|
+
finally:
|
|
543
|
+
self._turn_state.lease.end_workflow(execution)
|
|
544
|
+
if self._active is active:
|
|
545
|
+
self._active = None
|
|
546
|
+
if self._closing:
|
|
547
|
+
await self._hooks.close()
|
|
548
|
+
logger.debug("workflow run %s released the execution lease (session %s)", execution.run_id, session_id)
|
|
549
|
+
|
|
550
|
+
async def _load_run_settings(self, project_cwd: Path, *, request_id: str) -> Settings:
|
|
551
|
+
effective = await load_workflow_settings(
|
|
552
|
+
project_cwd, startup=self._startup_settings, handle=self._settings_handle
|
|
553
|
+
)
|
|
554
|
+
for warning in settings_warning_events(effective):
|
|
555
|
+
await self._bus.publish(replace(warning, request_id=request_id))
|
|
556
|
+
return effective.settings
|
|
557
|
+
|
|
558
|
+
async def _admit(self, event: WorkflowRunRequest, active: _ActiveRun) -> tuple[WorkflowRunner, WorkflowJournal]:
|
|
559
|
+
"""Everything between the reservation and the acceptance; raises :class:`_Rejection`."""
|
|
560
|
+
execution = active.execution
|
|
561
|
+
owner = WorkflowSessionOwner(
|
|
562
|
+
bus=self._bus,
|
|
563
|
+
persistence=self._persistence,
|
|
564
|
+
session_id=event.session_id or "",
|
|
565
|
+
workspace=event.target.workspace.materialize(),
|
|
566
|
+
)
|
|
567
|
+
active.owner = owner
|
|
568
|
+
active.session_id = owner.session.session_id or ""
|
|
569
|
+
try:
|
|
570
|
+
await owner.open(reconcile=True)
|
|
571
|
+
except WorkflowWorkspaceLocked as exc:
|
|
572
|
+
raise _Rejection(REJECT_WORKSPACE_LOCKED, str(exc)) from exc
|
|
573
|
+
except WorkflowSessionNotFound as exc:
|
|
574
|
+
raise _Rejection(REJECT_SESSION_NOT_FOUND, str(exc)) from exc
|
|
575
|
+
except WorkflowSessionInUse as exc:
|
|
576
|
+
raise _Rejection(REJECT_SESSION_IN_USE, str(exc)) from exc
|
|
577
|
+
except ValueError as exc:
|
|
578
|
+
raise _Rejection(REJECT_INVALID_REQUEST, str(exc)) from exc
|
|
579
|
+
if (
|
|
580
|
+
isinstance(event.target, WorkflowSessionSelection)
|
|
581
|
+
and owner.selection is not None
|
|
582
|
+
and owner.selection.identity != event.target.identity
|
|
583
|
+
):
|
|
584
|
+
raise _Rejection(REJECT_SPEC_CHANGED, "This session belongs to another workflow. Start a new session.")
|
|
585
|
+
workspace = owner.require_workspace()
|
|
586
|
+
if (missing := workspace.missing_primary()) is not None:
|
|
587
|
+
raise _Rejection(
|
|
588
|
+
REJECT_WORKING_DIR_MISSING,
|
|
589
|
+
f"The working directory no longer exists: {surrogate_safe_text(missing)}.",
|
|
590
|
+
)
|
|
591
|
+
config_dir = self._config_dir()
|
|
592
|
+
project_cwd = Path(workspace.primary_cwd)
|
|
593
|
+
settings = await self._load_run_settings(project_cwd, request_id=event.request_id)
|
|
594
|
+
if owner.state is not None and owner.state.model != event.target.model:
|
|
595
|
+
raise _Rejection(
|
|
596
|
+
REJECT_SESSION_CHANGED, "The workflow session model changed. Reload the session before starting."
|
|
597
|
+
)
|
|
598
|
+
selected = owner.state.model if owner.state is not None else event.target.model
|
|
599
|
+
settings, model = admission_settings(settings, selected, self._model_registry)
|
|
600
|
+
discovery = await asyncio.to_thread(discover_workflows, config_dir=config_dir, project_cwd=project_cwd)
|
|
601
|
+
source = discovery.find(event.target.workflow_id)
|
|
602
|
+
if source is None:
|
|
603
|
+
raise _Rejection(REJECT_WORKFLOW_NOT_FOUND, f"No workflow named {event.target.workflow_id!r} was found.")
|
|
604
|
+
identity = source.identity
|
|
605
|
+
if owner.selection is not None and owner.selection.identity != identity:
|
|
606
|
+
raise _Rejection(REJECT_SPEC_CHANGED, "This session belongs to another workflow. Start a new session.")
|
|
607
|
+
if event.pins is not None and event.pins.identity != identity:
|
|
608
|
+
raise _Rejection(REJECT_SPEC_CHANGED, "The workflow source differs from the prepared target.")
|
|
609
|
+
active.source = source
|
|
610
|
+
ledger: ConfirmationLedger | None = None
|
|
611
|
+
recorded: LedgerEntry | None = None
|
|
612
|
+
if source.source_kind != SOURCE_KIND_BUILTIN:
|
|
613
|
+
# Even preparation runs code: the metadata can name an arbitrary interpreter executable.
|
|
614
|
+
# Confirm the bytes before probing it; its fingerprint can only be checked after that probe.
|
|
615
|
+
ledger = await asyncio.to_thread(ConfirmationLedger, ledger_path(config_dir))
|
|
616
|
+
recorded = ledger.recorded(source.canonical_path, source.source_kind)
|
|
617
|
+
if recorded is None or recorded.entry_digest != source.source_digest:
|
|
618
|
+
raise _not_confirmed(source)
|
|
619
|
+
try:
|
|
620
|
+
sdk = await materialize_runtime_sdk(config_dir)
|
|
621
|
+
environment = await prepare_workflow_environment(source, sdk=sdk)
|
|
622
|
+
except WorkflowPreviewError as exc:
|
|
623
|
+
raise _Rejection(exc.code, exc.message) from exc
|
|
624
|
+
except OSError as exc:
|
|
625
|
+
raise _Rejection(REJECT_STORAGE_FAILED, f"The workflow SDK could not be materialized: {exc}") from exc
|
|
626
|
+
if event.pins is not None and event.pins.environment_fingerprint != environment.environment_fingerprint:
|
|
627
|
+
raise _Rejection(
|
|
628
|
+
REJECT_ENVIRONMENT_CHANGED, "The workflow's environment differs from the one that was confirmed."
|
|
629
|
+
)
|
|
630
|
+
if recorded is not None and recorded.environment_fingerprint != environment.environment_fingerprint:
|
|
631
|
+
raise _not_confirmed(source)
|
|
632
|
+
callbacks = WorkerCallbacks()
|
|
633
|
+
try:
|
|
634
|
+
loaded = await load_workflow(
|
|
635
|
+
source,
|
|
636
|
+
environment=environment,
|
|
637
|
+
sdk=sdk,
|
|
638
|
+
workspace=project_cwd,
|
|
639
|
+
bytecode_cache=worker_bytecode_cache_dir(config_dir),
|
|
640
|
+
ask_handler=callbacks.ask,
|
|
641
|
+
emit_handler=callbacks.emit,
|
|
642
|
+
)
|
|
643
|
+
except WorkflowPreviewError as exc:
|
|
644
|
+
raise _Rejection(exc.code, exc.message) from exc
|
|
645
|
+
try:
|
|
646
|
+
if event.pins is not None and event.pins.spec_digest != loaded.spec_digest:
|
|
647
|
+
raise _Rejection(REJECT_SPEC_CHANGED, "The workflow file changed since it was confirmed.")
|
|
648
|
+
if ledger is not None and not ledger.is_confirmed(
|
|
649
|
+
ledger_entry_for(source, loaded.load, loaded.spec_digest, environment, title=loaded.manifest["title"])
|
|
650
|
+
):
|
|
651
|
+
raise _not_confirmed(source)
|
|
652
|
+
try:
|
|
653
|
+
admitted = admit_manifest(
|
|
654
|
+
loaded.manifest,
|
|
655
|
+
agent_registry=self._agent_registry or AgentProfileRegistry(),
|
|
656
|
+
model_registry=self._model_registry,
|
|
657
|
+
settings=settings,
|
|
658
|
+
)
|
|
659
|
+
except AdmissionError as exc:
|
|
660
|
+
raise _Rejection(exc.code, exc.message) from exc
|
|
661
|
+
try:
|
|
662
|
+
await owner.prepare(
|
|
663
|
+
run_id=execution.run_id,
|
|
664
|
+
identity=identity,
|
|
665
|
+
title=admitted.graph.title,
|
|
666
|
+
settings=settings,
|
|
667
|
+
model_registry=self._model_registry,
|
|
668
|
+
hooks=self._build_hooks,
|
|
669
|
+
request_id=event.request_id,
|
|
670
|
+
has_agents=bool(admitted.resolved_nodes()),
|
|
671
|
+
)
|
|
672
|
+
except ValueError as exc:
|
|
673
|
+
raise _Rejection(REJECT_SPEC_CHANGED, str(exc)) from exc
|
|
674
|
+
owner.require_state().model = model
|
|
675
|
+
if self._session.surface is not None:
|
|
676
|
+
# Written by the admission save below; a discarded admission restores the previous surface.
|
|
677
|
+
owner.require_state().last_surface = self._session.surface.value
|
|
678
|
+
session = owner.session
|
|
679
|
+
session_id, session_dir = owner.require_session_id(), owner.require_session_dir()
|
|
680
|
+
header = RunHeader(
|
|
681
|
+
run_id=execution.run_id,
|
|
682
|
+
session_id=session_id,
|
|
683
|
+
workflow_id=source.workflow_id,
|
|
684
|
+
source_kind=source.source_kind,
|
|
685
|
+
canonical_path=source.canonical_path,
|
|
686
|
+
title=admitted.graph.title,
|
|
687
|
+
input_excerpt=event.input_text,
|
|
688
|
+
entry_digest=source.source_digest,
|
|
689
|
+
manifest_digest=loaded.load.manifest_digest,
|
|
690
|
+
schema_version=loaded.manifest["schema_version"],
|
|
691
|
+
spec_digest=loaded.spec_digest,
|
|
692
|
+
started_at=datetime.now(tz=UTC).isoformat(),
|
|
693
|
+
mode=self._mode.value,
|
|
694
|
+
model=model,
|
|
695
|
+
)
|
|
696
|
+
store: WorkflowRunStore | None = None
|
|
697
|
+
directory = run_dir(session_dir, execution.run_id)
|
|
698
|
+
try:
|
|
699
|
+
await finish_close(asyncio.create_task(owner.save()))
|
|
700
|
+
store = WorkflowRunStore.open(
|
|
701
|
+
directory,
|
|
702
|
+
header=header,
|
|
703
|
+
spec=RunSpec(loaded.manifest, asdict(environment), admitted.resolved_nodes()),
|
|
704
|
+
input_text=event.input_text,
|
|
705
|
+
source=source.source,
|
|
706
|
+
)
|
|
707
|
+
owner.commit_admission()
|
|
708
|
+
except BaseException as exc:
|
|
709
|
+
|
|
710
|
+
async def discard() -> None:
|
|
711
|
+
if store is not None:
|
|
712
|
+
await store.close()
|
|
713
|
+
if directory.exists():
|
|
714
|
+
await asyncio.to_thread(shutil.rmtree, directory)
|
|
715
|
+
await owner.discard_admission()
|
|
716
|
+
if not event.session_id and self._persistence.state_store is not None:
|
|
717
|
+
await self._persistence.state_store.delete_session(session_id, allow_active=True)
|
|
718
|
+
|
|
719
|
+
await finish_close(asyncio.create_task(discard()))
|
|
720
|
+
if isinstance(exc, (WorkflowStorageFailed, OSError)):
|
|
721
|
+
raise _Rejection(REJECT_STORAGE_FAILED, str(exc)) from exc
|
|
722
|
+
raise
|
|
723
|
+
except BaseException:
|
|
724
|
+
await loaded.client.close()
|
|
725
|
+
raise
|
|
726
|
+
journal = WorkflowJournal(store, self._bus, session_id=session_id)
|
|
727
|
+
resources = AgentNodeResources(
|
|
728
|
+
bus=self._bus,
|
|
729
|
+
session_id=session_id,
|
|
730
|
+
session_dir=session_dir,
|
|
731
|
+
approval_anchor=event.input_text,
|
|
732
|
+
usage_publisher=owner.usage,
|
|
733
|
+
workspace=workspace,
|
|
734
|
+
settings=settings,
|
|
735
|
+
approval_mode=lambda: self._session.approval_mode,
|
|
736
|
+
approval_judge_for=owner.judge_for,
|
|
737
|
+
hook_manager=session.hook_manager,
|
|
738
|
+
mutation_tracker=session.mutation_tracker,
|
|
739
|
+
mutation_coordinator=session.mutation_coordinator,
|
|
740
|
+
spill_quota=session.spill_quota,
|
|
741
|
+
allow_user_interaction=self._allow_user_interaction,
|
|
742
|
+
mcp_cache=self._mcp_cache,
|
|
743
|
+
agent_registry=self._agent_registry,
|
|
744
|
+
model_registry=self._model_registry,
|
|
745
|
+
)
|
|
746
|
+
if owner.trajectory is None:
|
|
747
|
+
raise RuntimeError("Preparing a workflow runner requires a session trajectory.")
|
|
748
|
+
runner = WorkflowRunner(
|
|
749
|
+
admitted=admitted,
|
|
750
|
+
journal=journal,
|
|
751
|
+
worker=loaded.client,
|
|
752
|
+
load_stdout=loaded.load.stdout,
|
|
753
|
+
resources=resources,
|
|
754
|
+
checkpoint=owner.checkpoint,
|
|
755
|
+
mode=self._mode,
|
|
756
|
+
timeout=event.timeout if event.timeout > 0 else None,
|
|
757
|
+
trace=WorkflowTrace(owner.trajectory.context(), run_id=execution.run_id, workflow_id=source.workflow_id),
|
|
758
|
+
)
|
|
759
|
+
callbacks.bind(runner)
|
|
760
|
+
|
|
761
|
+
return runner, journal
|
|
762
|
+
|
|
763
|
+
async def _reply(self, reply: WorkflowRunAccepted | WorkflowRunRejected) -> None:
|
|
764
|
+
_remember(self._replies, reply.request_id, reply, MAX_REMEMBERED_REPLIES)
|
|
765
|
+
await self._bus.publish(reply)
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
def _remember[T](cache: OrderedDict[str, T], key: str, value: T, limit: int) -> None:
|
|
769
|
+
cache[key] = value
|
|
770
|
+
while len(cache) > limit:
|
|
771
|
+
cache.popitem(last=False)
|