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,752 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""LAST_WORDS state: the Phase 4 progress note, its dropped-call manifest and the drop breaker.
|
|
4
|
+
|
|
5
|
+
Phase 4 (``current_turn_drop``) drops the current turn's tool-call history
|
|
6
|
+
and leaves a progress note in its place. ``LastWordsState`` stores that note
|
|
7
|
+
per logical turn, in the ``last_words`` slot of the reminder middleware's
|
|
8
|
+
per-turn container, and renders it as the ``[LAST_WORDS]`` block the
|
|
9
|
+
middleware appends after every other reminder on each call. Storage and
|
|
10
|
+
rendering stay one unit: ``create_reminder`` builds the middleware and this
|
|
11
|
+
state on one ``ReminderTurns``, and the compaction strategy is bound to both
|
|
12
|
+
at once (``UnifiedContextStrategy.bind_reminder``), so the state Phase 4
|
|
13
|
+
writes is the state the next request renders.
|
|
14
|
+
|
|
15
|
+
Lifetimes:
|
|
16
|
+
|
|
17
|
+
- attempt-local — a whole-run retry rolls them back with the messages they
|
|
18
|
+
describe (``Phase4RetrySnapshot``): the note, the todo text captured with
|
|
19
|
+
it, and the manifest;
|
|
20
|
+
- turn-monotonic — never rolled back: the breaker and the one
|
|
21
|
+
context-pressure notification per turn.
|
|
22
|
+
|
|
23
|
+
State restored from a saved session waits in a single-shot stash: the next
|
|
24
|
+
prepared turn takes it when it preserves LAST_WORDS (resuming the interrupted
|
|
25
|
+
turn) and discards it otherwise (``begin_turn``, then ``discard_restored``).
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import logging
|
|
31
|
+
from collections.abc import Mapping
|
|
32
|
+
from dataclasses import dataclass, replace
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from typing import TYPE_CHECKING, Any
|
|
35
|
+
|
|
36
|
+
from chrys.foundation.platform.files import is_utf8_encodable
|
|
37
|
+
from chrys.service.agent_middleware.reminders.todo import TodoSource
|
|
38
|
+
from chrys.service.agent_middleware.system_reminder import LAST_WORDS_PREFIX, wrap_system_reminder
|
|
39
|
+
|
|
40
|
+
from .spill import (
|
|
41
|
+
DISPLAY_ARGUMENT_DEFAULT_MAX_CHARS,
|
|
42
|
+
DISPLAY_ARGUMENT_PATH_MAX_CHARS,
|
|
43
|
+
DISPLAY_ARGUMENT_REASON_MAX_CHARS,
|
|
44
|
+
NOTE_RECORD_GROUP_ID,
|
|
45
|
+
NOTE_RECORD_TOOL_NAME,
|
|
46
|
+
available_record_path,
|
|
47
|
+
owned_record_directory_relative_path,
|
|
48
|
+
owned_record_relative_path,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if TYPE_CHECKING:
|
|
52
|
+
from collections.abc import Callable
|
|
53
|
+
|
|
54
|
+
from chrys.service.agent_middleware.system_reminder import ReminderTurns, TurnReminderState
|
|
55
|
+
|
|
56
|
+
from .spill import SpillQuota
|
|
57
|
+
|
|
58
|
+
logger = logging.getLogger(__name__)
|
|
59
|
+
|
|
60
|
+
_MANIFEST_MAX_LINES = 50
|
|
61
|
+
_MANIFEST_MAX_CHARS = 6_000
|
|
62
|
+
_MANIFEST_MAX_PERSISTED = 500
|
|
63
|
+
_MANIFEST_FIELD_MAX_CHARS = 1_024
|
|
64
|
+
_MANIFEST_TOOL_MAX_CHARS = 255
|
|
65
|
+
# State-field bound = the widest legal display_argument: a lone path segment
|
|
66
|
+
# or a command segment plus ", " plus a reason segment. Derived, so raising
|
|
67
|
+
# a per-key cap can never silently re-truncate stored values.
|
|
68
|
+
MANIFEST_DISPLAY_ARGUMENT_MAX_CHARS = max(
|
|
69
|
+
DISPLAY_ARGUMENT_PATH_MAX_CHARS,
|
|
70
|
+
DISPLAY_ARGUMENT_DEFAULT_MAX_CHARS + 2 + DISPLAY_ARGUMENT_REASON_MAX_CHARS,
|
|
71
|
+
)
|
|
72
|
+
_MANIFEST_STATUS_MAX_CHARS = 128
|
|
73
|
+
_MANIFEST_STRING_FIELD_LIMITS = {
|
|
74
|
+
"record_id": _MANIFEST_STATUS_MAX_CHARS,
|
|
75
|
+
"group_id": _MANIFEST_FIELD_MAX_CHARS,
|
|
76
|
+
"record_dir": _MANIFEST_FIELD_MAX_CHARS,
|
|
77
|
+
"relative_path": _MANIFEST_FIELD_MAX_CHARS,
|
|
78
|
+
"tool": _MANIFEST_TOOL_MAX_CHARS,
|
|
79
|
+
"display_argument": MANIFEST_DISPLAY_ARGUMENT_MAX_CHARS,
|
|
80
|
+
"outcome": _MANIFEST_STATUS_MAX_CHARS,
|
|
81
|
+
"no_record_reason": _MANIFEST_STATUS_MAX_CHARS,
|
|
82
|
+
}
|
|
83
|
+
_STATE_INTEGER_MAX = (1 << 63) - 1
|
|
84
|
+
_BREAKER_STATE_VERSION = 1
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass(frozen=True, slots=True)
|
|
88
|
+
class ManifestEntry:
|
|
89
|
+
"""One code-generated dropped-call stub stored as JSON-compatible state."""
|
|
90
|
+
|
|
91
|
+
record_id: str
|
|
92
|
+
group_id: str
|
|
93
|
+
record_dir: str
|
|
94
|
+
relative_path: str
|
|
95
|
+
turn: int
|
|
96
|
+
round: int
|
|
97
|
+
sequence: int
|
|
98
|
+
tool: str
|
|
99
|
+
display_argument: str
|
|
100
|
+
outcome: str
|
|
101
|
+
size_chars: int
|
|
102
|
+
assistant_text: bool = False
|
|
103
|
+
available: bool = True
|
|
104
|
+
no_record_reason: str = ""
|
|
105
|
+
|
|
106
|
+
def to_state(self) -> dict[str, Any]:
|
|
107
|
+
"""Return a JSON-compatible representation (never a dataclass instance)."""
|
|
108
|
+
return {
|
|
109
|
+
"record_id": _manifest_state_text(self.record_id, _MANIFEST_STATUS_MAX_CHARS),
|
|
110
|
+
"group_id": _manifest_state_text(self.group_id, _MANIFEST_FIELD_MAX_CHARS),
|
|
111
|
+
"record_dir": _manifest_state_text(self.record_dir, _MANIFEST_FIELD_MAX_CHARS),
|
|
112
|
+
"relative_path": _manifest_state_text(self.relative_path, _MANIFEST_FIELD_MAX_CHARS),
|
|
113
|
+
"turn": self.turn,
|
|
114
|
+
"round": self.round,
|
|
115
|
+
"sequence": self.sequence,
|
|
116
|
+
"tool": _manifest_state_text(self.tool, _MANIFEST_TOOL_MAX_CHARS),
|
|
117
|
+
"display_argument": _manifest_state_text(self.display_argument, MANIFEST_DISPLAY_ARGUMENT_MAX_CHARS),
|
|
118
|
+
"outcome": _manifest_state_text(self.outcome, _MANIFEST_STATUS_MAX_CHARS),
|
|
119
|
+
"size_chars": self.size_chars,
|
|
120
|
+
"assistant_text": self.assistant_text,
|
|
121
|
+
"available": self.available,
|
|
122
|
+
"no_record_reason": _manifest_state_text(self.no_record_reason, _MANIFEST_STATUS_MAX_CHARS),
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def from_state(cls, value: object) -> ManifestEntry | None:
|
|
127
|
+
"""Validate and restore one bounded manifest entry."""
|
|
128
|
+
if not isinstance(value, Mapping):
|
|
129
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: expected mapping")
|
|
130
|
+
return None
|
|
131
|
+
strings: dict[str, str] = {}
|
|
132
|
+
for key, limit in _MANIFEST_STRING_FIELD_LIMITS.items():
|
|
133
|
+
item = value.get(key, "")
|
|
134
|
+
if not isinstance(item, str) or len(item) > limit or not is_utf8_encodable(item):
|
|
135
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: invalid %s", key)
|
|
136
|
+
return None
|
|
137
|
+
strings[key] = item
|
|
138
|
+
record_dir = Path(strings["record_dir"])
|
|
139
|
+
relative_path = Path(strings["relative_path"]) if strings["relative_path"] else None
|
|
140
|
+
|
|
141
|
+
if not strings["group_id"] and strings["tool"] == NOTE_RECORD_TOOL_NAME:
|
|
142
|
+
# Superseded-note entries persisted by the first note-records
|
|
143
|
+
# build carried an empty group_id, which this validator rejects;
|
|
144
|
+
# normalize the legacy shape so those sessions keep their note
|
|
145
|
+
# manifest line instead of silently losing it on restore.
|
|
146
|
+
strings["group_id"] = NOTE_RECORD_GROUP_ID
|
|
147
|
+
|
|
148
|
+
if not owned_record_directory_relative_path(record_dir):
|
|
149
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: unsafe record_dir")
|
|
150
|
+
return None
|
|
151
|
+
if relative_path is not None and (
|
|
152
|
+
not owned_record_relative_path(relative_path) or relative_path.parent != record_dir
|
|
153
|
+
):
|
|
154
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: unsafe relative_path")
|
|
155
|
+
return None
|
|
156
|
+
integer_fields = ("turn", "round", "sequence", "size_chars")
|
|
157
|
+
integers: dict[str, int] = {}
|
|
158
|
+
for key in integer_fields:
|
|
159
|
+
item = value.get(key)
|
|
160
|
+
if not isinstance(item, int) or isinstance(item, bool) or item < 0 or item > _STATE_INTEGER_MAX:
|
|
161
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: invalid %s", key)
|
|
162
|
+
return None
|
|
163
|
+
integers[key] = item
|
|
164
|
+
assistant_text = value.get("assistant_text", False)
|
|
165
|
+
available = value.get("available", True)
|
|
166
|
+
if not isinstance(assistant_text, bool) or not isinstance(available, bool):
|
|
167
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: invalid flags")
|
|
168
|
+
return None
|
|
169
|
+
if not strings["group_id"] or not strings["record_dir"] or not strings["tool"]:
|
|
170
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: missing required fields")
|
|
171
|
+
return None
|
|
172
|
+
if strings["relative_path"] and not strings["record_id"]:
|
|
173
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: path without record id")
|
|
174
|
+
return None
|
|
175
|
+
if not strings["relative_path"] and not strings["no_record_reason"]:
|
|
176
|
+
logger.debug("Dropping malformed LAST_WORDS manifest entry: neither record nor refusal")
|
|
177
|
+
return None
|
|
178
|
+
return cls(
|
|
179
|
+
record_id=strings["record_id"],
|
|
180
|
+
group_id=strings["group_id"],
|
|
181
|
+
record_dir=strings["record_dir"],
|
|
182
|
+
relative_path=strings["relative_path"],
|
|
183
|
+
turn=integers["turn"],
|
|
184
|
+
round=integers["round"],
|
|
185
|
+
sequence=integers["sequence"],
|
|
186
|
+
tool=strings["tool"],
|
|
187
|
+
display_argument=strings["display_argument"],
|
|
188
|
+
outcome=strings["outcome"],
|
|
189
|
+
size_chars=integers["size_chars"],
|
|
190
|
+
assistant_text=assistant_text,
|
|
191
|
+
available=available,
|
|
192
|
+
no_record_reason=strings["no_record_reason"],
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass(frozen=True, slots=True)
|
|
197
|
+
class DropRoundBreakerState:
|
|
198
|
+
"""Versioned, turn-scoped Phase-4 attempt and spend breaker."""
|
|
199
|
+
|
|
200
|
+
version: int = _BREAKER_STATE_VERSION
|
|
201
|
+
attempts: int = 0
|
|
202
|
+
consecutive_no_progress: int = 0
|
|
203
|
+
tail_override: bool = False
|
|
204
|
+
disabled: bool = False
|
|
205
|
+
side_call_tokens: int = 0
|
|
206
|
+
|
|
207
|
+
def to_state(self) -> dict[str, Any]:
|
|
208
|
+
"""Return the full JSON-compatible breaker state."""
|
|
209
|
+
return {
|
|
210
|
+
"version": self.version,
|
|
211
|
+
"attempts": self.attempts,
|
|
212
|
+
"consecutive_no_progress": self.consecutive_no_progress,
|
|
213
|
+
"tail_override": self.tail_override,
|
|
214
|
+
"disabled": self.disabled,
|
|
215
|
+
"side_call_tokens": self.side_call_tokens,
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@classmethod
|
|
219
|
+
def from_state(cls, value: object) -> DropRoundBreakerState | None:
|
|
220
|
+
"""Return a validated breaker state, or ``None`` for old/malformed data."""
|
|
221
|
+
version = value.get("version") if isinstance(value, Mapping) else None
|
|
222
|
+
if (
|
|
223
|
+
not isinstance(value, Mapping)
|
|
224
|
+
or not isinstance(version, int)
|
|
225
|
+
or isinstance(version, bool)
|
|
226
|
+
or version != _BREAKER_STATE_VERSION
|
|
227
|
+
):
|
|
228
|
+
logger.debug("Dropping malformed or unsupported Phase-4 breaker state")
|
|
229
|
+
return None
|
|
230
|
+
integers: dict[str, int] = {}
|
|
231
|
+
for key in ("attempts", "consecutive_no_progress", "side_call_tokens"):
|
|
232
|
+
item = value.get(key)
|
|
233
|
+
if not isinstance(item, int) or isinstance(item, bool) or item < 0 or item > _STATE_INTEGER_MAX:
|
|
234
|
+
logger.debug("Dropping malformed Phase-4 breaker state: invalid %s", key)
|
|
235
|
+
return None
|
|
236
|
+
integers[key] = item
|
|
237
|
+
tail_override = value.get("tail_override")
|
|
238
|
+
disabled = value.get("disabled")
|
|
239
|
+
if not isinstance(tail_override, bool) or not isinstance(disabled, bool):
|
|
240
|
+
logger.debug("Dropping malformed Phase-4 breaker state: invalid flags")
|
|
241
|
+
return None
|
|
242
|
+
return cls(
|
|
243
|
+
attempts=integers["attempts"],
|
|
244
|
+
consecutive_no_progress=integers["consecutive_no_progress"],
|
|
245
|
+
tail_override=tail_override,
|
|
246
|
+
disabled=disabled,
|
|
247
|
+
side_call_tokens=integers["side_call_tokens"],
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@dataclass(frozen=True, slots=True)
|
|
252
|
+
class Phase4RetrySnapshot:
|
|
253
|
+
"""Attempt-local LAST_WORDS state restored by whole-run retry rollback.
|
|
254
|
+
|
|
255
|
+
Breaker accounting and context-pressure delivery are deliberately absent:
|
|
256
|
+
they record real per-turn spend/safety side effects and remain monotonic
|
|
257
|
+
across outer provider retries. The content-bearing note, its todo
|
|
258
|
+
snapshot, and its active spill manifest instead describe messages dropped
|
|
259
|
+
by one attempt and must roll back with those messages.
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
last_words: str | None
|
|
263
|
+
last_words_todo: str | None
|
|
264
|
+
last_words_manifest: tuple[dict[str, Any], ...]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@dataclass
|
|
268
|
+
class LastWordsTurn:
|
|
269
|
+
"""One logical turn's LAST_WORDS slot in the reminder middleware's per-turn container.
|
|
270
|
+
|
|
271
|
+
Intentionally mutable, like the container that holds it: a note set in
|
|
272
|
+
an agent child task stays visible to the sibling retry/resume tasks that
|
|
273
|
+
continue the same turn.
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
note: str | None = None
|
|
277
|
+
todo: str | None = None
|
|
278
|
+
"""Todo-list text captured when the note was set/restored.
|
|
279
|
+
|
|
280
|
+
Captured, never read live: the LAST_WORDS block is rendered on every LLM
|
|
281
|
+
call, so a live provider read would change the request suffix after each
|
|
282
|
+
post-compaction ``todo_write`` — a free-running KV-cache break. The
|
|
283
|
+
captured text rides the note (same set/refresh/restore/preserve lifecycle).
|
|
284
|
+
"""
|
|
285
|
+
manifest: list[dict[str, Any]] | None = None
|
|
286
|
+
breaker: dict[str, Any] | None = None
|
|
287
|
+
# Deliberately not part of persisted breaker state: a restored disabled
|
|
288
|
+
# breaker should warn once in the newly resumed process.
|
|
289
|
+
context_pressure_notified: bool = False
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _format_manifest_size(char_count: int) -> str:
|
|
293
|
+
if char_count < 1_000:
|
|
294
|
+
return str(char_count)
|
|
295
|
+
return f"{char_count / 1_000:.1f}k"
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _manifest_state_text(value: str, max_chars: int) -> str:
|
|
299
|
+
"""Return bounded text that strict UTF-8 session persistence can encode."""
|
|
300
|
+
safe = value.encode("utf-8", errors="backslashreplace").decode("utf-8")
|
|
301
|
+
return safe[:max_chars]
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class LastWordsState:
|
|
305
|
+
"""The LAST_WORDS note, manifest and breaker of one reminder middleware's turns.
|
|
306
|
+
|
|
307
|
+
Reads fall back to the restored stash asymmetrically, as the session
|
|
308
|
+
save path relies on: the note and its captured todo text when no turn
|
|
309
|
+
container exists or its note is unset, the manifest and the breaker only
|
|
310
|
+
when no turn container exists.
|
|
311
|
+
"""
|
|
312
|
+
|
|
313
|
+
def __init__(
|
|
314
|
+
self,
|
|
315
|
+
turns: ReminderTurns,
|
|
316
|
+
*,
|
|
317
|
+
spill_quota: SpillQuota | None = None,
|
|
318
|
+
session_root: Path | None = None,
|
|
319
|
+
file_read_available: bool = False,
|
|
320
|
+
todo_provider: Callable[[], str | None] | None = None,
|
|
321
|
+
) -> None:
|
|
322
|
+
self._turns = turns
|
|
323
|
+
self._spill_quota = spill_quota
|
|
324
|
+
self._session_root = session_root
|
|
325
|
+
self._file_read_available = file_read_available
|
|
326
|
+
# The note captures the todo list the catalog offers, read the same way.
|
|
327
|
+
self._todo = TodoSource(todo_provider)
|
|
328
|
+
# LAST_WORDS note restored from persisted session state (session
|
|
329
|
+
# resume). Consumed by the next preserving ``begin_turn`` so a
|
|
330
|
+
# post-restart retry/continue re-injects the note exactly like an
|
|
331
|
+
# in-process retry; discarded when a fresh turn starts instead.
|
|
332
|
+
self._restored_last_words: str | None = None
|
|
333
|
+
# Todo-list text captured alongside a restored LAST_WORDS note (same
|
|
334
|
+
# single-shot lifecycle as ``_restored_last_words``).
|
|
335
|
+
self._restored_last_words_todo: str | None = None
|
|
336
|
+
self._restored_last_words_manifest: list[dict[str, Any]] | None = None
|
|
337
|
+
self._restored_last_words_breaker: dict[str, Any] | None = None
|
|
338
|
+
|
|
339
|
+
@property
|
|
340
|
+
def turns(self) -> ReminderTurns:
|
|
341
|
+
"""The turn holder whose containers carry this state's slot."""
|
|
342
|
+
return self._turns
|
|
343
|
+
|
|
344
|
+
# ------------------------------------------------------------------
|
|
345
|
+
# Turn boundary (called by the reminder middleware's prepare_turn)
|
|
346
|
+
# ------------------------------------------------------------------
|
|
347
|
+
|
|
348
|
+
def begin_turn(self, previous: TurnReminderState | None, *, preserve: bool) -> LastWordsTurn:
|
|
349
|
+
"""The new turn's slot: carried over from *previous* or the stash when *preserve*, else empty.
|
|
350
|
+
|
|
351
|
+
A preserving turn with no *previous* container is a post-restart
|
|
352
|
+
retry/continue and takes the restored stash. The stash stays until
|
|
353
|
+
``discard_restored``, which ``prepare_turn`` calls once the rest of
|
|
354
|
+
the turn is captured.
|
|
355
|
+
"""
|
|
356
|
+
turn = LastWordsTurn()
|
|
357
|
+
if preserve:
|
|
358
|
+
if previous is not None:
|
|
359
|
+
carried = previous.last_words
|
|
360
|
+
if carried is not None:
|
|
361
|
+
turn.note = carried.note
|
|
362
|
+
turn.todo = carried.todo
|
|
363
|
+
turn.manifest = list(carried.manifest or []) or None
|
|
364
|
+
turn.breaker = dict(carried.breaker) if carried.breaker else None
|
|
365
|
+
turn.context_pressure_notified = carried.context_pressure_notified
|
|
366
|
+
else:
|
|
367
|
+
# Post-restart retry/continue: no in-memory turn state exists,
|
|
368
|
+
# fall back to the key family restored from persisted state.
|
|
369
|
+
turn.note = self._restored_last_words
|
|
370
|
+
turn.todo = self._restored_last_words_todo
|
|
371
|
+
turn.manifest = list(self._restored_last_words_manifest or []) or None
|
|
372
|
+
turn.breaker = dict(self._restored_last_words_breaker) if self._restored_last_words_breaker else None
|
|
373
|
+
return turn
|
|
374
|
+
|
|
375
|
+
def discard_restored(self) -> None:
|
|
376
|
+
"""Drop the restored stash: it is single-shot, taken or discarded by the turn just prepared."""
|
|
377
|
+
self._restored_last_words = None
|
|
378
|
+
self._restored_last_words_todo = None
|
|
379
|
+
self._restored_last_words_manifest = None
|
|
380
|
+
self._restored_last_words_breaker = None
|
|
381
|
+
|
|
382
|
+
@staticmethod
|
|
383
|
+
def record_paths(turn: LastWordsTurn) -> set[str]:
|
|
384
|
+
"""The record paths *turn*'s manifest lists.
|
|
385
|
+
|
|
386
|
+
Legacy restored sessions did not persist the archive pointer's
|
|
387
|
+
turn-start count; excluding these from the live count is the best
|
|
388
|
+
compatible approximation, but new saves never rely on it.
|
|
389
|
+
"""
|
|
390
|
+
return {
|
|
391
|
+
entry.relative_path
|
|
392
|
+
for value in turn.manifest or []
|
|
393
|
+
if (entry := ManifestEntry.from_state(value)) is not None and entry.relative_path
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
# ------------------------------------------------------------------
|
|
397
|
+
# Note, manifest and breaker
|
|
398
|
+
# ------------------------------------------------------------------
|
|
399
|
+
|
|
400
|
+
def set_last_words(self, text: str | None) -> None:
|
|
401
|
+
"""Set/clear the Phase 4 LAST_WORDS progress note.
|
|
402
|
+
|
|
403
|
+
Called by ``UnifiedContextStrategy`` after Phase 4 drops the
|
|
404
|
+
current turn's tool-call history. The text is appended (as a
|
|
405
|
+
``<system-reminder>`` block) to the end of the user message's
|
|
406
|
+
content array on every subsequent LLM call until the next turn.
|
|
407
|
+
|
|
408
|
+
The current todo-list text is captured here, once, so the dynamic
|
|
409
|
+
block only changes when the note itself changes (set/refresh/restore)
|
|
410
|
+
— never per call.
|
|
411
|
+
"""
|
|
412
|
+
turn = self._ensure_turn()
|
|
413
|
+
turn.note = text or None
|
|
414
|
+
turn.todo = self._todo.snapshot() if turn.note else None
|
|
415
|
+
|
|
416
|
+
def get_last_words(self) -> str | None:
|
|
417
|
+
"""Return the current LAST_WORDS text (for incremental regeneration).
|
|
418
|
+
|
|
419
|
+
Falls back to a restored-but-not-yet-consumed note so that saving a
|
|
420
|
+
session that was restored and closed again without resuming the turn
|
|
421
|
+
does not erase the persisted note.
|
|
422
|
+
"""
|
|
423
|
+
turn = self._current_turn()
|
|
424
|
+
if turn is not None and turn.note is not None:
|
|
425
|
+
return turn.note
|
|
426
|
+
return self._restored_last_words
|
|
427
|
+
|
|
428
|
+
def append_manifest(self, entries: list[ManifestEntry]) -> None:
|
|
429
|
+
"""Append code-generated stubs, retaining the newest persisted entries."""
|
|
430
|
+
if not entries:
|
|
431
|
+
return
|
|
432
|
+
turn = self._ensure_turn()
|
|
433
|
+
serialized = [*list(turn.manifest or []), *(entry.to_state() for entry in entries)]
|
|
434
|
+
turn.manifest = serialized[-_MANIFEST_MAX_PERSISTED:]
|
|
435
|
+
|
|
436
|
+
def mark_manifest_records_unavailable(self, relative_paths: frozenset[str] | set[str]) -> None:
|
|
437
|
+
"""Snapshot quota evictions into already-persisted manifest entries."""
|
|
438
|
+
if not relative_paths:
|
|
439
|
+
return
|
|
440
|
+
turn = self._ensure_turn()
|
|
441
|
+
if not turn.manifest:
|
|
442
|
+
return
|
|
443
|
+
updated: list[dict[str, Any]] = []
|
|
444
|
+
for value in turn.manifest:
|
|
445
|
+
entry = ManifestEntry.from_state(value)
|
|
446
|
+
if entry is None:
|
|
447
|
+
continue
|
|
448
|
+
if entry.relative_path in relative_paths and entry.available:
|
|
449
|
+
entry = replace(entry, available=False)
|
|
450
|
+
updated.append(entry.to_state())
|
|
451
|
+
turn.manifest = updated or None
|
|
452
|
+
|
|
453
|
+
def get_last_words_manifest(self) -> list[dict[str, Any]]:
|
|
454
|
+
"""Return detached manifest state with current quota evictions applied."""
|
|
455
|
+
state = self._turns.current()
|
|
456
|
+
if state is None:
|
|
457
|
+
source = self._restored_last_words_manifest
|
|
458
|
+
else:
|
|
459
|
+
source = state.last_words.manifest if state.last_words is not None else None
|
|
460
|
+
return self._normalize_active_manifest(source)
|
|
461
|
+
|
|
462
|
+
def snapshot_phase4_retry_state(self) -> Phase4RetrySnapshot:
|
|
463
|
+
"""Snapshot only the attempt-local, content-bearing Phase-4 state."""
|
|
464
|
+
turn = self._ensure_turn()
|
|
465
|
+
manifest = self._normalize_active_manifest(turn.manifest)
|
|
466
|
+
return Phase4RetrySnapshot(
|
|
467
|
+
last_words=turn.note,
|
|
468
|
+
last_words_todo=turn.todo,
|
|
469
|
+
last_words_manifest=tuple(manifest),
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
def restore_phase4_retry_state(self, snapshot: Phase4RetrySnapshot) -> None:
|
|
473
|
+
"""Restore LAST_WORDS content without rewinding turn-level safety accounting."""
|
|
474
|
+
turn = self._ensure_turn()
|
|
475
|
+
turn.note = snapshot.last_words
|
|
476
|
+
# This is the todo text captured when the note was created. Re-reading
|
|
477
|
+
# the live todo provider here would change the restored note's context.
|
|
478
|
+
turn.todo = snapshot.last_words_todo
|
|
479
|
+
manifest = self._normalize_active_manifest(snapshot.last_words_manifest)
|
|
480
|
+
turn.manifest = manifest or None
|
|
481
|
+
|
|
482
|
+
def get_drop_round_breaker(self) -> DropRoundBreakerState:
|
|
483
|
+
"""Return the active/restored Phase-4 breaker, defaulting empty."""
|
|
484
|
+
state = self._turns.current()
|
|
485
|
+
if state is None:
|
|
486
|
+
source = self._restored_last_words_breaker
|
|
487
|
+
else:
|
|
488
|
+
source = state.last_words.breaker if state.last_words is not None else None
|
|
489
|
+
restored = DropRoundBreakerState.from_state(source) if source is not None else None
|
|
490
|
+
return restored or DropRoundBreakerState()
|
|
491
|
+
|
|
492
|
+
def set_drop_round_breaker(self, breaker: DropRoundBreakerState) -> None:
|
|
493
|
+
"""Unconditionally replace breaker state, including note-less failures."""
|
|
494
|
+
self._ensure_turn().breaker = breaker.to_state()
|
|
495
|
+
|
|
496
|
+
def get_last_words_breaker_state(self) -> dict[str, Any] | None:
|
|
497
|
+
"""Return persisted breaker state once Phase 4 has recorded activity."""
|
|
498
|
+
breaker = self.get_drop_round_breaker()
|
|
499
|
+
return breaker.to_state() if breaker != DropRoundBreakerState() else None
|
|
500
|
+
|
|
501
|
+
def claim_context_pressure_notification(self) -> bool:
|
|
502
|
+
"""Claim the one context-pressure notification allowed per logical turn."""
|
|
503
|
+
turn = self._ensure_turn()
|
|
504
|
+
if turn.context_pressure_notified:
|
|
505
|
+
return False
|
|
506
|
+
turn.context_pressure_notified = True
|
|
507
|
+
return True
|
|
508
|
+
|
|
509
|
+
def release_context_pressure_notification(self) -> None:
|
|
510
|
+
"""Release a failed synchronous notification attempt for a later retry."""
|
|
511
|
+
self._ensure_turn().context_pressure_notified = False
|
|
512
|
+
|
|
513
|
+
# ------------------------------------------------------------------
|
|
514
|
+
# Session restore
|
|
515
|
+
# ------------------------------------------------------------------
|
|
516
|
+
|
|
517
|
+
def restore(
|
|
518
|
+
self,
|
|
519
|
+
state: Mapping[str, Any],
|
|
520
|
+
*,
|
|
521
|
+
available_relative_paths: frozenset[str] | set[str] | None = None,
|
|
522
|
+
) -> None:
|
|
523
|
+
"""Stash the persisted note, manifest and breaker for the next preserving turn."""
|
|
524
|
+
self.restore_last_words(state.get("last_words"))
|
|
525
|
+
self.restore_last_words_manifest(
|
|
526
|
+
state.get("last_words_manifest"),
|
|
527
|
+
available_relative_paths=available_relative_paths,
|
|
528
|
+
)
|
|
529
|
+
self.restore_last_words_breaker(state.get("last_words_breaker"))
|
|
530
|
+
|
|
531
|
+
def restore_last_words(self, text: str | None) -> None:
|
|
532
|
+
"""Stash a LAST_WORDS note restored from persisted session state.
|
|
533
|
+
|
|
534
|
+
Session restore calls this on a freshly built state (no turn state
|
|
535
|
+
exists yet). The next ``prepare_turn(preserve_last_words=True)``
|
|
536
|
+
— i.e. resuming the interrupted turn — picks the note up so the
|
|
537
|
+
request after restart carries the same ``[LAST_WORDS]`` reminder an
|
|
538
|
+
in-process retry would; starting a fresh turn discards it instead.
|
|
539
|
+
|
|
540
|
+
The todo section is re-captured from the (already hydrated) tracker —
|
|
541
|
+
callers must restore ``chrys_todos`` before restoring the note.
|
|
542
|
+
"""
|
|
543
|
+
self._restored_last_words = text or None
|
|
544
|
+
self._restored_last_words_todo = self._todo.snapshot() if self._restored_last_words else None
|
|
545
|
+
|
|
546
|
+
def restore_last_words_manifest(
|
|
547
|
+
self,
|
|
548
|
+
value: object,
|
|
549
|
+
*,
|
|
550
|
+
available_relative_paths: frozenset[str] | set[str] | None = None,
|
|
551
|
+
) -> None:
|
|
552
|
+
"""Validate restored manifest state and snapshot record availability once."""
|
|
553
|
+
if value is not None and not isinstance(value, list):
|
|
554
|
+
logger.debug("Dropping malformed LAST_WORDS manifest state: expected list")
|
|
555
|
+
raw_entries = value if isinstance(value, list) else []
|
|
556
|
+
entries = [entry for item in raw_entries if (entry := ManifestEntry.from_state(item)) is not None]
|
|
557
|
+
entries = entries[-_MANIFEST_MAX_PERSISTED:]
|
|
558
|
+
if available_relative_paths is None:
|
|
559
|
+
available_relative_paths = set()
|
|
560
|
+
if self._session_root is not None:
|
|
561
|
+
available_relative_paths = {
|
|
562
|
+
entry.relative_path
|
|
563
|
+
for entry in entries
|
|
564
|
+
if entry.relative_path and available_record_path(self._session_root, entry.relative_path)
|
|
565
|
+
}
|
|
566
|
+
restored: list[dict[str, Any]] = []
|
|
567
|
+
for entry in entries:
|
|
568
|
+
available = not entry.relative_path or entry.relative_path in available_relative_paths
|
|
569
|
+
restored.append(
|
|
570
|
+
ManifestEntry(
|
|
571
|
+
record_id=entry.record_id,
|
|
572
|
+
group_id=entry.group_id,
|
|
573
|
+
record_dir=entry.record_dir,
|
|
574
|
+
relative_path=entry.relative_path,
|
|
575
|
+
turn=entry.turn,
|
|
576
|
+
round=entry.round,
|
|
577
|
+
sequence=entry.sequence,
|
|
578
|
+
tool=entry.tool,
|
|
579
|
+
display_argument=entry.display_argument,
|
|
580
|
+
outcome=entry.outcome,
|
|
581
|
+
size_chars=entry.size_chars,
|
|
582
|
+
assistant_text=entry.assistant_text,
|
|
583
|
+
available=entry.available and available,
|
|
584
|
+
no_record_reason=entry.no_record_reason,
|
|
585
|
+
).to_state()
|
|
586
|
+
)
|
|
587
|
+
self._restored_last_words_manifest = restored or None
|
|
588
|
+
|
|
589
|
+
def restore_last_words_breaker(self, value: object) -> None:
|
|
590
|
+
"""Stash validated breaker state for the next preserving prepare."""
|
|
591
|
+
breaker = DropRoundBreakerState.from_state(value)
|
|
592
|
+
self._restored_last_words_breaker = breaker.to_state() if breaker is not None else None
|
|
593
|
+
|
|
594
|
+
# ------------------------------------------------------------------
|
|
595
|
+
# Rendering
|
|
596
|
+
# ------------------------------------------------------------------
|
|
597
|
+
|
|
598
|
+
def render(self) -> list[str]:
|
|
599
|
+
"""Build dynamic reminders that attach after the user message content.
|
|
600
|
+
|
|
601
|
+
A filesystem-free function of stored turn state plus the shared
|
|
602
|
+
in-memory spill ledger: the todo section is the text captured at
|
|
603
|
+
set/restore time, rendered INSIDE the ``[LAST_WORDS]``-prefixed string
|
|
604
|
+
(``refresh_last_words_reminder`` strips only ``[LAST_WORDS]``-prefixed
|
|
605
|
+
contents — a separately wrapped block would accumulate stale copies
|
|
606
|
+
across refreshes).
|
|
607
|
+
"""
|
|
608
|
+
reminders: list[str] = []
|
|
609
|
+
last_words = self.get_last_words()
|
|
610
|
+
manifest = self._current_manifest_entries()
|
|
611
|
+
if last_words or manifest:
|
|
612
|
+
# Task-anchored wording (§5.4): the reminder rides the LAST user
|
|
613
|
+
# message, which on an injected turn is an injection or a
|
|
614
|
+
# synthetic ``continue`` — "the above request" would anchor the
|
|
615
|
+
# agent on the wrong message. The ``[LAST_WORDS] `` prefix is
|
|
616
|
+
# load-bearing (the middleware strips by prefix match during
|
|
617
|
+
# refresh); keep it byte-identical.
|
|
618
|
+
text = (
|
|
619
|
+
f"{LAST_WORDS_PREFIX}You previously made progress on the current task "
|
|
620
|
+
"(the user's request and any follow-up messages above) but ran "
|
|
621
|
+
"out of context, so your earlier tool-call history for this "
|
|
622
|
+
"task has been dropped. The note below is your own updated progress "
|
|
623
|
+
"record — read it and resume from where you left off. Do NOT redo "
|
|
624
|
+
"work that the note says is already done. If the note says the "
|
|
625
|
+
"work is finished but you have not yet delivered the final reply "
|
|
626
|
+
"to the user, do not re-gather anything — compose and deliver "
|
|
627
|
+
"that reply now from the note."
|
|
628
|
+
)
|
|
629
|
+
if last_words:
|
|
630
|
+
text += "\n\n" + last_words.strip()
|
|
631
|
+
todo_section = self._current_last_words_todo()
|
|
632
|
+
if todo_section:
|
|
633
|
+
text += "\n\n" + todo_section
|
|
634
|
+
if manifest:
|
|
635
|
+
text += "\n\n" + self._render_manifest(manifest)
|
|
636
|
+
reminders.append(text)
|
|
637
|
+
return reminders
|
|
638
|
+
|
|
639
|
+
def render_last_words_reminder_text(self) -> str | None:
|
|
640
|
+
"""Render the LAST_WORDS reminder exactly as the next model call injects it.
|
|
641
|
+
|
|
642
|
+
Public debug-oriented view over ``render`` for callers (the compaction
|
|
643
|
+
strategy) that want to persist the injected text without
|
|
644
|
+
reimplementing the rendering. Each block carries the same
|
|
645
|
+
``<system-reminder>`` envelope and tag-escaping the enrichment path
|
|
646
|
+
applies, so the dump matches the wire prompt (on the wire the blocks
|
|
647
|
+
are separate content items of one message; here they join with a
|
|
648
|
+
blank line). ``None`` when no LAST_WORDS state exists and nothing
|
|
649
|
+
would be injected.
|
|
650
|
+
"""
|
|
651
|
+
reminders = self.render()
|
|
652
|
+
if not reminders:
|
|
653
|
+
return None
|
|
654
|
+
return "\n\n".join(wrap_system_reminder(reminder) for reminder in reminders)
|
|
655
|
+
|
|
656
|
+
# ------------------------------------------------------------------
|
|
657
|
+
# Internal helpers
|
|
658
|
+
# ------------------------------------------------------------------
|
|
659
|
+
|
|
660
|
+
def _current_turn(self) -> LastWordsTurn | None:
|
|
661
|
+
"""The current turn container's slot, if both exist."""
|
|
662
|
+
state = self._turns.current()
|
|
663
|
+
return state.last_words if state is not None else None
|
|
664
|
+
|
|
665
|
+
def _ensure_turn(self) -> LastWordsTurn:
|
|
666
|
+
"""The current turn's slot, creating an empty container and slot for this task if needed."""
|
|
667
|
+
state = self._turns.ensure()
|
|
668
|
+
if state.last_words is None:
|
|
669
|
+
state.last_words = LastWordsTurn()
|
|
670
|
+
return state.last_words
|
|
671
|
+
|
|
672
|
+
def _normalize_active_manifest(self, source: object) -> list[dict[str, Any]]:
|
|
673
|
+
"""Validate manifest rows and synchronize live spill availability."""
|
|
674
|
+
raw = source if isinstance(source, list | tuple) else ()
|
|
675
|
+
entries = [entry for value in raw if (entry := ManifestEntry.from_state(value)) is not None]
|
|
676
|
+
normalized: list[dict[str, Any]] = []
|
|
677
|
+
for entry in entries[-_MANIFEST_MAX_PERSISTED:]:
|
|
678
|
+
if (
|
|
679
|
+
entry.available
|
|
680
|
+
and entry.relative_path
|
|
681
|
+
and self._spill_quota is not None
|
|
682
|
+
and not self._spill_quota.is_record_available(entry.relative_path)
|
|
683
|
+
):
|
|
684
|
+
entry = replace(entry, available=False)
|
|
685
|
+
normalized.append(entry.to_state())
|
|
686
|
+
return normalized
|
|
687
|
+
|
|
688
|
+
def _current_manifest_entries(self) -> list[ManifestEntry]:
|
|
689
|
+
"""Restore validated dataclasses from the JSON-only turn state."""
|
|
690
|
+
return [
|
|
691
|
+
entry for value in self.get_last_words_manifest() if (entry := ManifestEntry.from_state(value)) is not None
|
|
692
|
+
]
|
|
693
|
+
|
|
694
|
+
def _render_manifest(self, entries: list[ManifestEntry]) -> str:
|
|
695
|
+
"""Render the bounded dropped-call appendix without filesystem access."""
|
|
696
|
+
record_dir = entries[-1].record_dir
|
|
697
|
+
absolute_dir = (
|
|
698
|
+
(self._session_root / record_dir).absolute().as_posix() if self._session_root is not None else record_dir
|
|
699
|
+
)
|
|
700
|
+
heading = f"--- Dropped this turn (records under {absolute_dir.rstrip('/')}/) ---"
|
|
701
|
+
rendered_entries = [self._render_manifest_entry(entry) for entry in entries]
|
|
702
|
+
omitted = 0
|
|
703
|
+
|
|
704
|
+
affordance = (
|
|
705
|
+
"To inspect archived input/output, read the listed file with read_file; "
|
|
706
|
+
"capped records contain an explicit middle-truncation marker."
|
|
707
|
+
if self._file_read_available and any(entry.available and entry.relative_path for entry in entries)
|
|
708
|
+
else ""
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
def _compose() -> str:
|
|
712
|
+
lines = [heading]
|
|
713
|
+
if omitted:
|
|
714
|
+
lines.append(f"… and {omitted} earlier records — see manifest.md")
|
|
715
|
+
lines.extend(rendered_entries)
|
|
716
|
+
if affordance:
|
|
717
|
+
lines.append(affordance)
|
|
718
|
+
return "\n".join(lines)
|
|
719
|
+
|
|
720
|
+
rendered = _compose()
|
|
721
|
+
while (
|
|
722
|
+
len(rendered) > _MANIFEST_MAX_CHARS or len(rendered.splitlines()) > _MANIFEST_MAX_LINES
|
|
723
|
+
) and rendered_entries:
|
|
724
|
+
rendered_entries.pop(0)
|
|
725
|
+
omitted += 1
|
|
726
|
+
rendered = _compose()
|
|
727
|
+
if len(rendered) > _MANIFEST_MAX_CHARS:
|
|
728
|
+
rendered = rendered[: _MANIFEST_MAX_CHARS - 1] + "…"
|
|
729
|
+
return rendered
|
|
730
|
+
|
|
731
|
+
@staticmethod
|
|
732
|
+
def _render_manifest_entry(entry: ManifestEntry) -> str:
|
|
733
|
+
size = _format_manifest_size(entry.size_chars)
|
|
734
|
+
if entry.assistant_text:
|
|
735
|
+
body = f"r{entry.round} {entry.sequence:03d} assistant text, {size} chars"
|
|
736
|
+
else:
|
|
737
|
+
argument = f"{entry.display_argument}" if entry.display_argument else "…"
|
|
738
|
+
body = f"r{entry.round} {entry.sequence:03d} {entry.tool}({argument}) → {entry.outcome}, {size} chars"
|
|
739
|
+
if entry.no_record_reason:
|
|
740
|
+
return f"{body} — (no record: {entry.no_record_reason})"
|
|
741
|
+
filename = Path(entry.relative_path).name
|
|
742
|
+
suffix = f" — {filename}"
|
|
743
|
+
if not entry.available:
|
|
744
|
+
suffix += " (record missing)"
|
|
745
|
+
return body + suffix
|
|
746
|
+
|
|
747
|
+
def _current_last_words_todo(self) -> str | None:
|
|
748
|
+
"""Todo text captured with the active LAST_WORDS note, if any."""
|
|
749
|
+
turn = self._current_turn()
|
|
750
|
+
if turn is not None and turn.note is not None:
|
|
751
|
+
return turn.todo
|
|
752
|
+
return self._restored_last_words_todo
|