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,714 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Engine-side trajectory recorder: session, turn, branch and fork anchors.
|
|
4
|
+
|
|
5
|
+
The engine owns one :class:`TrajectoryRecorder` for its lifetime; the
|
|
6
|
+
recorder owns one :class:`SessionTrajectory` per current session and the
|
|
7
|
+
turn it is currently tracing. Every lifecycle anchor calls in here —
|
|
8
|
+
``start()`` binds the session, ``shutdown()`` closes it before the empty
|
|
9
|
+
directory cleanup, the runner opens turns, the finalizer closes them,
|
|
10
|
+
rollback opens a new branch, fork writes the child's prelude. Everything
|
|
11
|
+
is best-effort: a disabled, degraded or missing recorder never changes what
|
|
12
|
+
the engine does.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import asyncio
|
|
18
|
+
import logging
|
|
19
|
+
from collections.abc import Callable, Mapping
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import TYPE_CHECKING, Any
|
|
23
|
+
|
|
24
|
+
from chrys.foundation.trajectory.context import TrajectoryContext
|
|
25
|
+
from chrys.foundation.trajectory.envelope import (
|
|
26
|
+
EventDraft,
|
|
27
|
+
MeasurementSource,
|
|
28
|
+
measurement,
|
|
29
|
+
monotonic_now_ns,
|
|
30
|
+
utc_now_rfc3339,
|
|
31
|
+
)
|
|
32
|
+
from chrys.foundation.trajectory.event_types import (
|
|
33
|
+
EventType,
|
|
34
|
+
ProfileKind,
|
|
35
|
+
RuntimeFinishReason,
|
|
36
|
+
SourceRefKind,
|
|
37
|
+
TurnEndReason,
|
|
38
|
+
TurnSuspendReason,
|
|
39
|
+
)
|
|
40
|
+
from chrys.foundation.trajectory.fingerprint import DOMAIN_WORKSPACE, fingerprint_text
|
|
41
|
+
from chrys.foundation.trajectory.ids import new_analytics_id
|
|
42
|
+
from chrys.service.trajectory.segmented import emit_segmented, emit_segmented_soon
|
|
43
|
+
from chrys.service.trajectory.session import SessionStartInfo, SessionTrajectory
|
|
44
|
+
from chrys.service.trajectory.state import TurnRecord, record_turn_started, turn_record
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from chrys.service.mutations.types import FileHashDiff
|
|
48
|
+
from chrys.service.profiles.models.schema import ModelProfile
|
|
49
|
+
from chrys.service.state.store import SessionCheckpoint
|
|
50
|
+
|
|
51
|
+
logger = logging.getLogger(__name__)
|
|
52
|
+
|
|
53
|
+
ROLLBACK_REASON_USER = "user_rollback"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def exchange_facts(
|
|
57
|
+
*,
|
|
58
|
+
agent_profile_name: str,
|
|
59
|
+
agent_profile_fingerprint: str,
|
|
60
|
+
model_profile: ModelProfile | None,
|
|
61
|
+
model_profile_fingerprint: str,
|
|
62
|
+
) -> dict[str, Any]:
|
|
63
|
+
"""Static ``model.exchange.*`` facts of one pass: which profiles the model was acquired under."""
|
|
64
|
+
facts: dict[str, Any] = {
|
|
65
|
+
"agent_profile_fingerprint": agent_profile_fingerprint,
|
|
66
|
+
"model_profile_fingerprint": model_profile_fingerprint,
|
|
67
|
+
}
|
|
68
|
+
# An unnamed profile (an engine built before one resolved) has no id to
|
|
69
|
+
# record: an empty id is not a valid identifier, and a rejected event
|
|
70
|
+
# would cost the whole exchange rather than one field.
|
|
71
|
+
if agent_profile_name:
|
|
72
|
+
facts["agent_profile_id"] = agent_profile_name
|
|
73
|
+
if model_profile is not None:
|
|
74
|
+
if model_profile.id:
|
|
75
|
+
facts["model_profile_id"] = model_profile.id
|
|
76
|
+
facts["provider"] = model_profile.provider
|
|
77
|
+
facts["api_style"] = model_profile.api_style
|
|
78
|
+
facts["request_model"] = model_profile.model_id
|
|
79
|
+
return facts
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass(slots=True)
|
|
83
|
+
class ActiveTurnTrace:
|
|
84
|
+
"""The turn the recorder is currently tracing."""
|
|
85
|
+
|
|
86
|
+
turn_id: str
|
|
87
|
+
turn_number: int
|
|
88
|
+
started_monotonic_ns: int
|
|
89
|
+
opened_at: str
|
|
90
|
+
suspended: bool = False
|
|
91
|
+
finished: bool = False
|
|
92
|
+
start_committed: bool = False
|
|
93
|
+
"""Set when the opening line took its sequence — the log owns it from then on."""
|
|
94
|
+
start_settlement: asyncio.Task[None] | None = None
|
|
95
|
+
"""The emit that writes the opening line; ``start_committed`` is only final once it is done."""
|
|
96
|
+
response_settled: bool = False
|
|
97
|
+
"""The post-finalizer fence was queued; prevents duplicate tail markers."""
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class TrajectoryRecorder:
|
|
101
|
+
"""Best-effort session/turn-level trajectory recording for one engine."""
|
|
102
|
+
|
|
103
|
+
def __init__(self) -> None:
|
|
104
|
+
self._trajectory: SessionTrajectory | None = None
|
|
105
|
+
self._turn: ActiveTurnTrace | None = None
|
|
106
|
+
self._close_task: asyncio.Task[None] | None = None
|
|
107
|
+
# Monotonic timestamp of the pending user interrupt request, consumed
|
|
108
|
+
# by the turn close that observes it.
|
|
109
|
+
self._interrupt_requested_ns: int | None = None
|
|
110
|
+
|
|
111
|
+
# ------------------------------------------------------------ inspection
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def trajectory(self) -> SessionTrajectory | None:
|
|
115
|
+
return self._trajectory
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def current_turn(self) -> ActiveTurnTrace | None:
|
|
119
|
+
return self._turn
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def current_turn_id(self) -> str | None:
|
|
123
|
+
turn = self._turn
|
|
124
|
+
return turn.turn_id if turn is not None and not turn.finished else None
|
|
125
|
+
|
|
126
|
+
def context(self) -> TrajectoryContext | None:
|
|
127
|
+
"""The ambient context a model run of the current turn binds."""
|
|
128
|
+
trajectory = self._open()
|
|
129
|
+
if trajectory is None:
|
|
130
|
+
return None
|
|
131
|
+
return trajectory.context(turn_id=self.current_turn_id)
|
|
132
|
+
|
|
133
|
+
def finished_turn_context(self) -> TrajectoryContext | None:
|
|
134
|
+
"""Context retaining the just-finished turn for its finalizer tail hooks."""
|
|
135
|
+
trajectory = self._open()
|
|
136
|
+
if trajectory is None:
|
|
137
|
+
return None
|
|
138
|
+
turn = self._turn
|
|
139
|
+
return trajectory.context(turn_id=turn.turn_id if turn is not None else None)
|
|
140
|
+
|
|
141
|
+
# ------------------------------------------------------------- lifecycle
|
|
142
|
+
|
|
143
|
+
def bind_session(
|
|
144
|
+
self,
|
|
145
|
+
*,
|
|
146
|
+
session_id: str,
|
|
147
|
+
session_dir: Path | None,
|
|
148
|
+
write_lock_path: Path | None,
|
|
149
|
+
session_start_info: Callable[[], SessionStartInfo | None],
|
|
150
|
+
on_activation_failed: Callable[[str], None] | None = None,
|
|
151
|
+
) -> SessionTrajectory:
|
|
152
|
+
"""Bind the recorder to *session_id* (idempotent for the same open session).
|
|
153
|
+
|
|
154
|
+
Activation — opening the log, taking the writer lease, writing the
|
|
155
|
+
runtime prelude — happens on the first event, so a session that
|
|
156
|
+
never records anything never creates ``trajectory/``.
|
|
157
|
+
"""
|
|
158
|
+
existing = self._trajectory
|
|
159
|
+
if existing is not None and existing.session_id == session_id and not existing.is_closed:
|
|
160
|
+
return existing
|
|
161
|
+
self._trajectory = SessionTrajectory(
|
|
162
|
+
session_id=session_id,
|
|
163
|
+
session_dir=session_dir,
|
|
164
|
+
write_lock_path=write_lock_path,
|
|
165
|
+
session_start_info=session_start_info,
|
|
166
|
+
on_activation_failed=on_activation_failed,
|
|
167
|
+
)
|
|
168
|
+
self._turn = None
|
|
169
|
+
self._close_task = None
|
|
170
|
+
self._interrupt_requested_ns = None
|
|
171
|
+
return self._trajectory
|
|
172
|
+
|
|
173
|
+
async def close(self, *, reason: str = RuntimeFinishReason.GRACEFUL_SHUTDOWN) -> None:
|
|
174
|
+
"""Close the current session's recorder (idempotent)."""
|
|
175
|
+
trajectory = self._trajectory
|
|
176
|
+
if trajectory is None:
|
|
177
|
+
return
|
|
178
|
+
task = self._close_task
|
|
179
|
+
if task is None:
|
|
180
|
+
task = asyncio.ensure_future(self._close_runtime(trajectory, reason=reason))
|
|
181
|
+
self._close_task = task
|
|
182
|
+
# One task for the open turn's terminal and the close behind it: the
|
|
183
|
+
# close is what stops the worker and hands its descriptor and this
|
|
184
|
+
# session's writer lease back, so a caller that stops waiting part way
|
|
185
|
+
# through must not be able to leave the runtime open holding them.
|
|
186
|
+
await asyncio.shield(task)
|
|
187
|
+
|
|
188
|
+
async def _close_runtime(self, trajectory: SessionTrajectory, *, reason: str) -> None:
|
|
189
|
+
if not trajectory.is_closed:
|
|
190
|
+
turn = self._turn
|
|
191
|
+
if turn is not None and not turn.finished:
|
|
192
|
+
# A turn still open when the runtime closes is ended by the
|
|
193
|
+
# close itself (the finalizer did not get to run — e.g. the
|
|
194
|
+
# run task was cancelled during shutdown); a hard crash leaves
|
|
195
|
+
# it dangling on purpose, which is how a later runtime tells
|
|
196
|
+
# the two apart.
|
|
197
|
+
end_reason = (
|
|
198
|
+
TurnEndReason.PROCESS_EXIT
|
|
199
|
+
if reason == RuntimeFinishReason.GRACEFUL_SHUTDOWN
|
|
200
|
+
else TurnEndReason.CANCELLED
|
|
201
|
+
)
|
|
202
|
+
await self.turn_finished(end_reason=end_reason)
|
|
203
|
+
try:
|
|
204
|
+
await trajectory.close(reason=reason)
|
|
205
|
+
except Exception:
|
|
206
|
+
logger.warning("Trajectory close failed for session %s", trajectory.session_id, exc_info=True)
|
|
207
|
+
if self._trajectory is not trajectory:
|
|
208
|
+
# A new session bound while this close was still running (its
|
|
209
|
+
# caller was cancelled and moved on): that recorder is live, and
|
|
210
|
+
# clearing it here would unbind a runtime nobody asked to close.
|
|
211
|
+
return
|
|
212
|
+
self._trajectory = None
|
|
213
|
+
self._turn = None
|
|
214
|
+
self._interrupt_requested_ns = None
|
|
215
|
+
|
|
216
|
+
# ----------------------------------------------------------------- turns
|
|
217
|
+
|
|
218
|
+
async def turn_started(
|
|
219
|
+
self,
|
|
220
|
+
*,
|
|
221
|
+
turn_number: int,
|
|
222
|
+
is_retry: bool,
|
|
223
|
+
agent_profile_fingerprint: str,
|
|
224
|
+
model_profile_fingerprint: str,
|
|
225
|
+
primary_cwd: str,
|
|
226
|
+
history_state: dict[str, Any] | None,
|
|
227
|
+
opening_item_id: str | None = None,
|
|
228
|
+
preparation_scope_operation_id: str | None = None,
|
|
229
|
+
) -> str | None:
|
|
230
|
+
"""Open a new ``turn_id`` for the pass about to run; returns it.
|
|
231
|
+
|
|
232
|
+
``workspace_revision`` is the keyed fingerprint of *primary_cwd* —
|
|
233
|
+
the same value ``session.started`` carries — so a mid-session
|
|
234
|
+
workspace change shows up as a different revision without the path
|
|
235
|
+
itself ever reaching the log.
|
|
236
|
+
"""
|
|
237
|
+
trajectory = self._open()
|
|
238
|
+
if trajectory is None:
|
|
239
|
+
return None
|
|
240
|
+
trace = ActiveTurnTrace(
|
|
241
|
+
turn_id=new_analytics_id(),
|
|
242
|
+
turn_number=turn_number,
|
|
243
|
+
started_monotonic_ns=monotonic_now_ns(),
|
|
244
|
+
opened_at=utc_now_rfc3339(),
|
|
245
|
+
)
|
|
246
|
+
self._turn = trace
|
|
247
|
+
payload: dict[str, Any] = {
|
|
248
|
+
"turn_id": trace.turn_id,
|
|
249
|
+
"turn_number": turn_number,
|
|
250
|
+
"opened_at": trace.opened_at,
|
|
251
|
+
"agent_profile_fingerprint": agent_profile_fingerprint,
|
|
252
|
+
"model_profile_fingerprint": model_profile_fingerprint,
|
|
253
|
+
"is_retry": is_retry,
|
|
254
|
+
}
|
|
255
|
+
if opening_item_id is not None:
|
|
256
|
+
payload["opening_item_id"] = opening_item_id
|
|
257
|
+
if preparation_scope_operation_id is not None:
|
|
258
|
+
payload["preparation_scope_operation_id"] = preparation_scope_operation_id
|
|
259
|
+
draft = EventDraft(
|
|
260
|
+
event_type=EventType.TURN_STARTED,
|
|
261
|
+
actor=trajectory.main_actor,
|
|
262
|
+
turn_id=trace.turn_id,
|
|
263
|
+
payload=payload,
|
|
264
|
+
occurred_at=trace.opened_at,
|
|
265
|
+
monotonic_ns=trace.started_monotonic_ns,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def _payload(sequence: int) -> Mapping[str, Any]:
|
|
269
|
+
# Resolved at write time: the fingerprint key is loaded by the
|
|
270
|
+
# activation this very emit may have triggered, and the registry
|
|
271
|
+
# names the sequence the turn.started line actually landed at.
|
|
272
|
+
# Reaching here is also what makes the turn real to the log: the
|
|
273
|
+
# writer takes the sequence and queues the line in one locked step.
|
|
274
|
+
trace.start_committed = True
|
|
275
|
+
key = trajectory.fingerprint_key
|
|
276
|
+
payload["workspace_revision"] = (
|
|
277
|
+
fingerprint_text(key, DOMAIN_WORKSPACE, primary_cwd) if key is not None and primary_cwd else ""
|
|
278
|
+
)
|
|
279
|
+
if history_state is not None:
|
|
280
|
+
record_turn_started(
|
|
281
|
+
history_state,
|
|
282
|
+
TurnRecord(turn_number=turn_number, turn_id=trace.turn_id, started_sequence=sequence),
|
|
283
|
+
is_retry=is_retry,
|
|
284
|
+
)
|
|
285
|
+
return payload
|
|
286
|
+
|
|
287
|
+
# The opening line rides a task of the recorder's own, shielded from
|
|
288
|
+
# this caller: an interrupt here unwinds the caller while the emit it
|
|
289
|
+
# started runs on — a cancelled ``to_thread`` activation goes on
|
|
290
|
+
# opening the log and writing the draft that triggered it anyway.
|
|
291
|
+
# Whether the line took a sequence therefore has no answer while this
|
|
292
|
+
# task is alive, only once it settles, which is what the terminal
|
|
293
|
+
# waits for.
|
|
294
|
+
settlement = asyncio.create_task(_emit(trajectory, draft, payload_factory=_payload))
|
|
295
|
+
trace.start_settlement = settlement
|
|
296
|
+
await asyncio.shield(settlement)
|
|
297
|
+
return trace.turn_id
|
|
298
|
+
|
|
299
|
+
async def turn_finished(self, *, end_reason: str) -> None:
|
|
300
|
+
"""Close the current turn with a terminal ``end_reason`` (once)."""
|
|
301
|
+
trajectory = self._open()
|
|
302
|
+
turn = self._turn
|
|
303
|
+
if trajectory is None or turn is None or turn.finished:
|
|
304
|
+
return
|
|
305
|
+
if not turn.start_committed and turn.start_settlement is not None:
|
|
306
|
+
# An opening line that has not taken a sequence *yet* and one that
|
|
307
|
+
# never will read the same from here, and only the emit itself
|
|
308
|
+
# tells them apart — by settling. A close that guessed would be
|
|
309
|
+
# racing a thread that is still writing, so it waits instead.
|
|
310
|
+
await asyncio.wait([turn.start_settlement])
|
|
311
|
+
if not turn.start_committed:
|
|
312
|
+
# Settled without a sequence: nothing is left that could still
|
|
313
|
+
# give the start one. A terminal against a start nothing recorded
|
|
314
|
+
# is not a shape readers handle; an unclosed span is one they
|
|
315
|
+
# already do, so the turn is dropped rather than closed. Only the
|
|
316
|
+
# terminal is held to this — the turn's other events name their
|
|
317
|
+
# turn, they do not close it.
|
|
318
|
+
self._turn = None
|
|
319
|
+
return
|
|
320
|
+
now_ns = monotonic_now_ns()
|
|
321
|
+
closed_at = utc_now_rfc3339()
|
|
322
|
+
requested_ns, self._interrupt_requested_ns = self._interrupt_requested_ns, None
|
|
323
|
+
if end_reason == TurnEndReason.INTERRUPTED and requested_ns is not None:
|
|
324
|
+
# "User pressed interrupt" and "the run actually stopped" are two
|
|
325
|
+
# moments; the second is observed here, at the turn's close.
|
|
326
|
+
await _emit(
|
|
327
|
+
trajectory,
|
|
328
|
+
EventDraft(
|
|
329
|
+
event_type=EventType.INTERRUPT_OBSERVED,
|
|
330
|
+
actor=trajectory.main_actor,
|
|
331
|
+
turn_id=turn.turn_id,
|
|
332
|
+
payload={
|
|
333
|
+
"target_operation_id": None,
|
|
334
|
+
"target_turn_id": turn.turn_id,
|
|
335
|
+
"observed_at": closed_at,
|
|
336
|
+
"observed_after_ms": _elapsed_ms(requested_ns, now_ns),
|
|
337
|
+
},
|
|
338
|
+
measurements={
|
|
339
|
+
"/payload/observed_after_ms": measurement(MeasurementSource.MONOTONIC_CLOCK, method_version=1)
|
|
340
|
+
},
|
|
341
|
+
occurred_at=closed_at,
|
|
342
|
+
monotonic_ns=now_ns,
|
|
343
|
+
),
|
|
344
|
+
)
|
|
345
|
+
# Marked closed only once nothing is left to await before the terminal
|
|
346
|
+
# line: an interrupt in the observation above would otherwise leave a
|
|
347
|
+
# turn the shutdown repair then skips as already finished.
|
|
348
|
+
turn.finished = True
|
|
349
|
+
await _emit(
|
|
350
|
+
trajectory,
|
|
351
|
+
EventDraft(
|
|
352
|
+
event_type=EventType.TURN_FINISHED,
|
|
353
|
+
actor=trajectory.main_actor,
|
|
354
|
+
turn_id=turn.turn_id,
|
|
355
|
+
payload={
|
|
356
|
+
"turn_id": turn.turn_id,
|
|
357
|
+
"closed_at": closed_at,
|
|
358
|
+
"duration_ms": _elapsed_ms(turn.started_monotonic_ns, now_ns),
|
|
359
|
+
"end_reason": end_reason,
|
|
360
|
+
},
|
|
361
|
+
measurements={"/payload/duration_ms": measurement(MeasurementSource.MONOTONIC_CLOCK, method_version=1)},
|
|
362
|
+
occurred_at=closed_at,
|
|
363
|
+
monotonic_ns=now_ns,
|
|
364
|
+
),
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
async def turn_response_settled(
|
|
368
|
+
self,
|
|
369
|
+
*,
|
|
370
|
+
outcome: str,
|
|
371
|
+
drained_scopes: list[str],
|
|
372
|
+
waited_hook_operation_ids: list[str],
|
|
373
|
+
) -> None:
|
|
374
|
+
"""Write the zero-weight response fence after every finalizer tail step."""
|
|
375
|
+
prepared = self._prepare_turn_response_settled(
|
|
376
|
+
outcome=outcome,
|
|
377
|
+
drained_scopes=drained_scopes,
|
|
378
|
+
waited_hook_operation_ids=waited_hook_operation_ids,
|
|
379
|
+
)
|
|
380
|
+
if prepared is not None:
|
|
381
|
+
context, payload = prepared
|
|
382
|
+
await emit_segmented(
|
|
383
|
+
context,
|
|
384
|
+
event_type=EventType.TURN_RESPONSE_SETTLED,
|
|
385
|
+
payload=payload,
|
|
386
|
+
array_fields={"/payload/waited_hook_operation_ids": waited_hook_operation_ids},
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
def turn_response_settled_soon(
|
|
390
|
+
self,
|
|
391
|
+
*,
|
|
392
|
+
outcome: str,
|
|
393
|
+
drained_scopes: list[str],
|
|
394
|
+
waited_hook_operation_ids: list[str],
|
|
395
|
+
) -> None:
|
|
396
|
+
"""Queue the response fence while unwinding from cancellation."""
|
|
397
|
+
prepared = self._prepare_turn_response_settled(
|
|
398
|
+
outcome=outcome,
|
|
399
|
+
drained_scopes=drained_scopes,
|
|
400
|
+
waited_hook_operation_ids=waited_hook_operation_ids,
|
|
401
|
+
)
|
|
402
|
+
if prepared is not None:
|
|
403
|
+
context, payload = prepared
|
|
404
|
+
emit_segmented_soon(
|
|
405
|
+
context,
|
|
406
|
+
event_type=EventType.TURN_RESPONSE_SETTLED,
|
|
407
|
+
payload=payload,
|
|
408
|
+
array_fields={"/payload/waited_hook_operation_ids": waited_hook_operation_ids},
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
def _prepare_turn_response_settled(
|
|
412
|
+
self,
|
|
413
|
+
*,
|
|
414
|
+
outcome: str,
|
|
415
|
+
drained_scopes: list[str],
|
|
416
|
+
waited_hook_operation_ids: list[str],
|
|
417
|
+
) -> tuple[TrajectoryContext, dict[str, Any]] | None:
|
|
418
|
+
trajectory = self._open()
|
|
419
|
+
turn = self._turn
|
|
420
|
+
if trajectory is None or turn is None or not turn.finished or turn.response_settled:
|
|
421
|
+
return None
|
|
422
|
+
turn.response_settled = True
|
|
423
|
+
return (
|
|
424
|
+
trajectory.context(turn_id=turn.turn_id),
|
|
425
|
+
{
|
|
426
|
+
"outcome": outcome,
|
|
427
|
+
"drained_scopes": list(drained_scopes),
|
|
428
|
+
"waited_hook_operation_count": len(waited_hook_operation_ids),
|
|
429
|
+
},
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
def interrupt_requested_soon(self, *, source: str = "user", scope: str = "turn") -> None:
|
|
433
|
+
"""Record a user interrupt against the open turn (queued in order, ack not awaited).
|
|
434
|
+
|
|
435
|
+
The line takes its sequence here, ahead of the terminals the interrupt
|
|
436
|
+
is about to produce, so the log still reads in the order things
|
|
437
|
+
happened. The acknowledgement is not waited on: everything this
|
|
438
|
+
interrupt has to reach — the executor, every live sub-agent — comes
|
|
439
|
+
after the call, and a backend that has stopped acknowledging writes
|
|
440
|
+
must not keep tools running while it is waited out.
|
|
441
|
+
"""
|
|
442
|
+
trajectory = self._open()
|
|
443
|
+
turn = self._turn
|
|
444
|
+
if trajectory is None or turn is None or turn.finished:
|
|
445
|
+
return
|
|
446
|
+
now_ns = monotonic_now_ns()
|
|
447
|
+
if self._interrupt_requested_ns is None:
|
|
448
|
+
self._interrupt_requested_ns = now_ns
|
|
449
|
+
requested_at = utc_now_rfc3339()
|
|
450
|
+
_emit_soon(
|
|
451
|
+
trajectory,
|
|
452
|
+
EventDraft(
|
|
453
|
+
event_type=EventType.INTERRUPT_REQUESTED,
|
|
454
|
+
actor=trajectory.main_actor,
|
|
455
|
+
turn_id=turn.turn_id,
|
|
456
|
+
payload={
|
|
457
|
+
"source": source,
|
|
458
|
+
"scope": scope,
|
|
459
|
+
"target_operation_id": None,
|
|
460
|
+
"target_turn_id": turn.turn_id,
|
|
461
|
+
"reason_code": "user_interrupt",
|
|
462
|
+
"requested_at": requested_at,
|
|
463
|
+
},
|
|
464
|
+
occurred_at=requested_at,
|
|
465
|
+
monotonic_ns=now_ns,
|
|
466
|
+
),
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
async def turn_suspended(self) -> None:
|
|
470
|
+
trajectory = self._open()
|
|
471
|
+
turn = self._turn
|
|
472
|
+
if trajectory is None or turn is None or turn.finished or turn.suspended:
|
|
473
|
+
return
|
|
474
|
+
turn.suspended = True
|
|
475
|
+
await _emit(
|
|
476
|
+
trajectory,
|
|
477
|
+
EventDraft(
|
|
478
|
+
event_type=EventType.TURN_SUSPENDED,
|
|
479
|
+
actor=trajectory.main_actor,
|
|
480
|
+
turn_id=turn.turn_id,
|
|
481
|
+
payload={"turn_id": turn.turn_id, "reason": TurnSuspendReason.AWAITING_SUB_AGENTS},
|
|
482
|
+
),
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
async def turn_resumed(self) -> None:
|
|
486
|
+
trajectory = self._open()
|
|
487
|
+
turn = self._turn
|
|
488
|
+
if trajectory is None or turn is None or turn.finished or not turn.suspended:
|
|
489
|
+
return
|
|
490
|
+
turn.suspended = False
|
|
491
|
+
await _emit(
|
|
492
|
+
trajectory,
|
|
493
|
+
EventDraft(
|
|
494
|
+
event_type=EventType.TURN_RESUMED,
|
|
495
|
+
actor=trajectory.main_actor,
|
|
496
|
+
turn_id=turn.turn_id,
|
|
497
|
+
payload={"turn_id": turn.turn_id},
|
|
498
|
+
),
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
async def checkpoint(self) -> None:
|
|
502
|
+
"""Write a durable ``trajectory.checkpoint`` (after a turn-end save)."""
|
|
503
|
+
trajectory = self._open()
|
|
504
|
+
if trajectory is None or not trajectory.is_active:
|
|
505
|
+
return
|
|
506
|
+
try:
|
|
507
|
+
await trajectory.checkpoint()
|
|
508
|
+
except Exception:
|
|
509
|
+
logger.debug("Trajectory checkpoint failed", exc_info=True)
|
|
510
|
+
|
|
511
|
+
# --------------------------------------------------------- derived facts
|
|
512
|
+
|
|
513
|
+
async def mutation_summary(
|
|
514
|
+
self,
|
|
515
|
+
summary: Mapping[str, FileHashDiff],
|
|
516
|
+
*,
|
|
517
|
+
checkpoint: SessionCheckpoint | None,
|
|
518
|
+
) -> None:
|
|
519
|
+
"""Emit the per-turn ``tool.mutation_batch.summary`` (counts only)."""
|
|
520
|
+
trajectory = self._open()
|
|
521
|
+
turn = self._turn
|
|
522
|
+
if trajectory is None or turn is None or not summary:
|
|
523
|
+
return
|
|
524
|
+
created = modified = deleted = net_zero = proven = assumed = 0
|
|
525
|
+
for diff in summary.values():
|
|
526
|
+
if diff.is_net_zero:
|
|
527
|
+
net_zero += 1
|
|
528
|
+
if not diff.before_exists and diff.after_exists:
|
|
529
|
+
created += 1
|
|
530
|
+
elif diff.before_exists and not diff.after_exists:
|
|
531
|
+
deleted += 1
|
|
532
|
+
else:
|
|
533
|
+
modified += 1
|
|
534
|
+
if diff.inferred or diff.content_unavailable:
|
|
535
|
+
assumed += 1
|
|
536
|
+
else:
|
|
537
|
+
proven += 1
|
|
538
|
+
payload: dict[str, Any] = {
|
|
539
|
+
"turn_id": turn.turn_id,
|
|
540
|
+
"files_touched": len(summary),
|
|
541
|
+
"create": created,
|
|
542
|
+
"modify": modified,
|
|
543
|
+
"delete": deleted,
|
|
544
|
+
"net_zero_count": net_zero,
|
|
545
|
+
"proven_count": proven,
|
|
546
|
+
"assumed_count": assumed,
|
|
547
|
+
"derived_at": utc_now_rfc3339(),
|
|
548
|
+
}
|
|
549
|
+
if checkpoint is not None and checkpoint.session_checkpoint_id:
|
|
550
|
+
payload["source_ref"] = {
|
|
551
|
+
"kind": SourceRefKind.SESSION_CHECKPOINT,
|
|
552
|
+
"id": checkpoint.session_checkpoint_id,
|
|
553
|
+
"hash": checkpoint.content_hash,
|
|
554
|
+
}
|
|
555
|
+
await _emit(
|
|
556
|
+
trajectory,
|
|
557
|
+
EventDraft(
|
|
558
|
+
event_type=EventType.TOOL_MUTATION_BATCH_SUMMARY,
|
|
559
|
+
actor=trajectory.main_actor,
|
|
560
|
+
turn_id=turn.turn_id,
|
|
561
|
+
operation_id=new_analytics_id(),
|
|
562
|
+
payload=payload,
|
|
563
|
+
measurements={
|
|
564
|
+
"/payload/files_touched": measurement(MeasurementSource.DERIVED_FROM_SESSION, method_version=1)
|
|
565
|
+
},
|
|
566
|
+
),
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
# ----------------------------------------------- profile / branch / fork
|
|
570
|
+
|
|
571
|
+
async def profile_switched(self, *, kind: str, from_fingerprint: str, to_fingerprint: str) -> None:
|
|
572
|
+
trajectory = self._open()
|
|
573
|
+
if trajectory is None or from_fingerprint == to_fingerprint:
|
|
574
|
+
return
|
|
575
|
+
if kind not in {ProfileKind.AGENT, ProfileKind.MODEL}:
|
|
576
|
+
return
|
|
577
|
+
await _emit(
|
|
578
|
+
trajectory,
|
|
579
|
+
EventDraft(
|
|
580
|
+
event_type=EventType.PROFILE_SWITCHED,
|
|
581
|
+
actor=trajectory.main_actor,
|
|
582
|
+
turn_id=self.current_turn_id,
|
|
583
|
+
payload={"kind": kind, "from_fingerprint": from_fingerprint, "to_fingerprint": to_fingerprint},
|
|
584
|
+
),
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
async def ensure_active(self) -> None:
|
|
588
|
+
"""Open the log now, before the caller takes the session write lock.
|
|
589
|
+
|
|
590
|
+
Activation recovers a torn tail under that same lock and does it from
|
|
591
|
+
a worker thread, so a log first opened *inside* the lock waits for the
|
|
592
|
+
holder that is waiting for it: the wait ends at the activation timeout
|
|
593
|
+
and the log gives up on recording. The flows that reset a session hold
|
|
594
|
+
the lock and record across it, so they open it first.
|
|
595
|
+
"""
|
|
596
|
+
trajectory = self._open()
|
|
597
|
+
if trajectory is None:
|
|
598
|
+
return
|
|
599
|
+
await trajectory.ensure_active()
|
|
600
|
+
|
|
601
|
+
async def rollback(self, *, target_turn: int, history_state: dict[str, Any] | None) -> None:
|
|
602
|
+
"""Open a new branch: ``session.rollback`` then ``branch.superseded``.
|
|
603
|
+
|
|
604
|
+
A snapshot rollback calls this after its atomic swap and before
|
|
605
|
+
restore; a welcome rollback calls it after the reset has committed and
|
|
606
|
+
rebound the recorder. In both cases the session write lock is released
|
|
607
|
+
first. *history_state* is the captured registry that still names the
|
|
608
|
+
target turn and the first superseded turn.
|
|
609
|
+
"""
|
|
610
|
+
trajectory = self._open()
|
|
611
|
+
if trajectory is None:
|
|
612
|
+
return
|
|
613
|
+
# The branch being superseded is only known once the log is open, and
|
|
614
|
+
# a rollback can be the first thing a runtime records: activating
|
|
615
|
+
# lazily on the emit below would name no old branch at all and let
|
|
616
|
+
# activation overwrite the new one.
|
|
617
|
+
await trajectory.ensure_active()
|
|
618
|
+
old_branch = trajectory.branch_id
|
|
619
|
+
new_branch = new_analytics_id()
|
|
620
|
+
superseded_from = turn_record(history_state, target_turn + 1)
|
|
621
|
+
target = turn_record(history_state, target_turn) if target_turn > 0 else None
|
|
622
|
+
payload: dict[str, Any] = {"new_branch_id": new_branch, "reason_code": ROLLBACK_REASON_USER}
|
|
623
|
+
if old_branch is not None:
|
|
624
|
+
payload["old_branch_id"] = old_branch
|
|
625
|
+
if superseded_from is not None:
|
|
626
|
+
payload["superseded_from_sequence"] = superseded_from.started_sequence
|
|
627
|
+
if target is not None:
|
|
628
|
+
payload["target_turn_id"] = target.turn_id
|
|
629
|
+
|
|
630
|
+
def _payload(sequence: int) -> Mapping[str, Any]:
|
|
631
|
+
if superseded_from is not None:
|
|
632
|
+
payload["superseded_to_sequence"] = sequence - 1
|
|
633
|
+
return payload
|
|
634
|
+
|
|
635
|
+
# The turn being traced (if any) belongs to the superseded branch.
|
|
636
|
+
self._turn = None
|
|
637
|
+
self._interrupt_requested_ns = None
|
|
638
|
+
trajectory.set_branch_id(new_branch)
|
|
639
|
+
await _emit(
|
|
640
|
+
trajectory,
|
|
641
|
+
EventDraft(event_type=EventType.SESSION_ROLLBACK, actor=trajectory.main_actor),
|
|
642
|
+
payload_factory=_payload,
|
|
643
|
+
)
|
|
644
|
+
if old_branch is not None:
|
|
645
|
+
await _emit(
|
|
646
|
+
trajectory,
|
|
647
|
+
EventDraft(
|
|
648
|
+
event_type=EventType.BRANCH_SUPERSEDED,
|
|
649
|
+
actor=trajectory.main_actor,
|
|
650
|
+
payload={"branch_id": old_branch, "superseded_by": new_branch},
|
|
651
|
+
),
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
async def fork(
|
|
655
|
+
self,
|
|
656
|
+
*,
|
|
657
|
+
origin_session_id: str,
|
|
658
|
+
fork_session_id: str,
|
|
659
|
+
fork_session_dir: Path,
|
|
660
|
+
fork_write_lock_path: Path | None,
|
|
661
|
+
session_start_info: SessionStartInfo | None,
|
|
662
|
+
) -> None:
|
|
663
|
+
"""Write the fork's own opening runtime (``session.forked``).
|
|
664
|
+
|
|
665
|
+
The directory arrives resolved: the state store owns the layout, so
|
|
666
|
+
nothing here may derive one session's path from another's.
|
|
667
|
+
"""
|
|
668
|
+
from chrys.service.trajectory.fork import record_fork
|
|
669
|
+
|
|
670
|
+
trajectory = self._trajectory
|
|
671
|
+
forked_at = trajectory.last_assigned_sequence() if trajectory is not None else 0
|
|
672
|
+
try:
|
|
673
|
+
await record_fork(
|
|
674
|
+
fork_session_id=fork_session_id,
|
|
675
|
+
fork_session_dir=fork_session_dir,
|
|
676
|
+
fork_write_lock_path=fork_write_lock_path,
|
|
677
|
+
origin_session_id=origin_session_id,
|
|
678
|
+
forked_at_sequence=forked_at,
|
|
679
|
+
session_start_info=session_start_info,
|
|
680
|
+
)
|
|
681
|
+
except Exception:
|
|
682
|
+
logger.warning("Failed to record trajectory fork for %s", fork_session_id, exc_info=True)
|
|
683
|
+
|
|
684
|
+
# ------------------------------------------------------------- internals
|
|
685
|
+
|
|
686
|
+
def _open(self) -> SessionTrajectory | None:
|
|
687
|
+
trajectory = self._trajectory
|
|
688
|
+
if trajectory is None or trajectory.is_closed:
|
|
689
|
+
return None
|
|
690
|
+
return trajectory
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
def _elapsed_ms(start_ns: int, end_ns: int) -> int:
|
|
694
|
+
return max(0, (end_ns - start_ns) // 1_000_000)
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
async def _emit(
|
|
698
|
+
trajectory: SessionTrajectory,
|
|
699
|
+
draft: EventDraft,
|
|
700
|
+
*,
|
|
701
|
+
payload_factory: Callable[[int], Mapping[str, Any]] | None = None,
|
|
702
|
+
) -> None:
|
|
703
|
+
try:
|
|
704
|
+
await trajectory.emit(draft, payload_factory=payload_factory)
|
|
705
|
+
except Exception:
|
|
706
|
+
logger.debug("Trajectory emit failed (%s)", draft.event_type, exc_info=True)
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
def _emit_soon(trajectory: SessionTrajectory, draft: EventDraft) -> None:
|
|
710
|
+
"""Queue *draft* in sequence order without waiting for its acknowledgement."""
|
|
711
|
+
try:
|
|
712
|
+
trajectory.emit_soon(draft)
|
|
713
|
+
except Exception:
|
|
714
|
+
logger.debug("Trajectory emit failed (%s)", draft.event_type, exc_info=True)
|