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,187 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Atomic catalog bundles and safe semantic-message rendering."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import gettext
|
|
8
|
+
import logging
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from enum import StrEnum
|
|
12
|
+
from functools import cache
|
|
13
|
+
|
|
14
|
+
from chrys.foundation.i18n import formatting as _formatting
|
|
15
|
+
from chrys.foundation.i18n.catalogs import CatalogLoadError, CatalogRoot, load_catalog
|
|
16
|
+
from chrys.foundation.i18n.formatting import format_message, has_visible_content, validate_authored_template
|
|
17
|
+
from chrys.foundation.i18n.locale import ENGLISH_LOCALE, normalize_locale
|
|
18
|
+
from chrys.foundation.i18n.messages import MessageRef, _render_arguments
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CatalogWarningCode(StrEnum):
|
|
24
|
+
"""Stable kinds of catalog warning returned to composition roots."""
|
|
25
|
+
|
|
26
|
+
LOAD_FAILED = "i18n_catalog_load_failed"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True, slots=True)
|
|
30
|
+
class CatalogLoadWarning:
|
|
31
|
+
"""Typed notice that a requested catalog could not replace English."""
|
|
32
|
+
|
|
33
|
+
requested_locale: str
|
|
34
|
+
code: CatalogWarningCode = field(default=CatalogWarningCode.LOAD_FAILED, init=False)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
type _TemplateValidator = Callable[[str, bool], frozenset[str] | None]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True, slots=True)
|
|
41
|
+
class _CatalogBundle:
|
|
42
|
+
locale_name: str
|
|
43
|
+
translations: gettext.GNUTranslations | None
|
|
44
|
+
validate_template: _TemplateValidator | None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(frozen=True, slots=True)
|
|
48
|
+
class _LocalizerState:
|
|
49
|
+
requested_locale: str
|
|
50
|
+
bundle: _CatalogBundle
|
|
51
|
+
first_load_warning: CatalogLoadWarning | None = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
_ENGLISH_BUNDLE = _CatalogBundle(
|
|
55
|
+
locale_name=ENGLISH_LOCALE,
|
|
56
|
+
translations=None,
|
|
57
|
+
validate_template=None,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Localizer:
|
|
62
|
+
"""Render ``MessageRef`` values through one atomically replaceable bundle."""
|
|
63
|
+
|
|
64
|
+
__slots__ = ("_catalog_root", "_state")
|
|
65
|
+
|
|
66
|
+
def __init__(self, requested_locale: str, *, catalog_root: CatalogRoot | None = None) -> None:
|
|
67
|
+
self._catalog_root = catalog_root
|
|
68
|
+
self._state = _LocalizerState(requested_locale=requested_locale, bundle=_ENGLISH_BUNDLE)
|
|
69
|
+
|
|
70
|
+
effective_locale = normalize_locale(requested_locale)
|
|
71
|
+
if effective_locale == ENGLISH_LOCALE:
|
|
72
|
+
return
|
|
73
|
+
try:
|
|
74
|
+
bundle = self._build_bundle(effective_locale)
|
|
75
|
+
except CatalogLoadError:
|
|
76
|
+
logger.warning("Requested i18n catalog unavailable; using English.")
|
|
77
|
+
self._state = _LocalizerState(
|
|
78
|
+
requested_locale=requested_locale,
|
|
79
|
+
bundle=_ENGLISH_BUNDLE,
|
|
80
|
+
first_load_warning=CatalogLoadWarning(requested_locale=requested_locale),
|
|
81
|
+
)
|
|
82
|
+
return
|
|
83
|
+
self._state = _LocalizerState(requested_locale=requested_locale, bundle=bundle)
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def requested_locale(self) -> str:
|
|
87
|
+
"""Return the persisted/requested locale value without rewriting it."""
|
|
88
|
+
return self._state.requested_locale
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def effective_locale(self) -> str:
|
|
92
|
+
"""Return the locale of the currently active immutable bundle."""
|
|
93
|
+
return self._state.bundle.locale_name
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def first_load_warning(self) -> CatalogLoadWarning | None:
|
|
97
|
+
"""Return the typed warning produced by a failed initial catalog load."""
|
|
98
|
+
return self._state.first_load_warning
|
|
99
|
+
|
|
100
|
+
def switch_locale(self, requested_locale: str) -> CatalogLoadWarning | None:
|
|
101
|
+
"""Build and atomically install a locale bundle, retaining state on failure."""
|
|
102
|
+
prior = self._state
|
|
103
|
+
effective_locale = normalize_locale(requested_locale)
|
|
104
|
+
if effective_locale == prior.bundle.locale_name:
|
|
105
|
+
self._state = _LocalizerState(requested_locale=requested_locale, bundle=prior.bundle)
|
|
106
|
+
return None
|
|
107
|
+
if effective_locale == ENGLISH_LOCALE:
|
|
108
|
+
self._state = _LocalizerState(requested_locale=requested_locale, bundle=_ENGLISH_BUNDLE)
|
|
109
|
+
return None
|
|
110
|
+
try:
|
|
111
|
+
bundle = self._build_bundle(effective_locale)
|
|
112
|
+
except CatalogLoadError:
|
|
113
|
+
logger.warning("Requested i18n catalog unavailable; keeping active locale.")
|
|
114
|
+
return CatalogLoadWarning(requested_locale=requested_locale)
|
|
115
|
+
self._state = _LocalizerState(requested_locale=requested_locale, bundle=bundle)
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
def render(self, reference: MessageRef) -> str:
|
|
119
|
+
"""Render a bound semantic message through the active locale bundle."""
|
|
120
|
+
bundle = self._state.bundle
|
|
121
|
+
translations = bundle.translations
|
|
122
|
+
if translations is None:
|
|
123
|
+
return format_message(reference)
|
|
124
|
+
|
|
125
|
+
definition = reference.definition
|
|
126
|
+
plural_id = f"{definition.key}#plural"
|
|
127
|
+
try:
|
|
128
|
+
# ZeroDivisionError: a loadable MO's Plural-Forms expression may
|
|
129
|
+
# divide by zero only once ngettext evaluates it for a count.
|
|
130
|
+
if reference.count is None:
|
|
131
|
+
template = translations.gettext(definition.key)
|
|
132
|
+
lookup_ids = {definition.key}
|
|
133
|
+
else:
|
|
134
|
+
template = translations.ngettext(definition.key, plural_id, reference.count)
|
|
135
|
+
lookup_ids = {definition.key, plural_id}
|
|
136
|
+
except LookupError, OSError, TypeError, ValueError, ZeroDivisionError:
|
|
137
|
+
logger.warning("Invalid i18n catalog lookup; using English fallback.")
|
|
138
|
+
return format_message(reference)
|
|
139
|
+
|
|
140
|
+
if _formatting._normalized_lookup_candidate(template) in lookup_ids:
|
|
141
|
+
logger.debug("Missing i18n catalog entry; using English fallback.")
|
|
142
|
+
return format_message(reference)
|
|
143
|
+
|
|
144
|
+
validator = bundle.validate_template
|
|
145
|
+
if validator is None:
|
|
146
|
+
return format_message(reference)
|
|
147
|
+
names = validator(template, definition.multiline)
|
|
148
|
+
if names is None:
|
|
149
|
+
logger.warning("Invalid i18n catalog entry; using English fallback.")
|
|
150
|
+
return format_message(reference)
|
|
151
|
+
|
|
152
|
+
parameters = _render_arguments(reference)
|
|
153
|
+
parameter_names = set(parameters)
|
|
154
|
+
if names - {"count"} != parameter_names - {"count"} or ("count" in names and "count" not in parameter_names):
|
|
155
|
+
logger.warning("Invalid i18n catalog entry; using English fallback.")
|
|
156
|
+
return format_message(reference)
|
|
157
|
+
try:
|
|
158
|
+
translated = template.format_map(parameters)
|
|
159
|
+
except KeyError, ValueError:
|
|
160
|
+
logger.warning("Invalid i18n catalog entry; using English fallback.")
|
|
161
|
+
return format_message(reference)
|
|
162
|
+
if not has_visible_content(translated):
|
|
163
|
+
logger.warning("Invalid i18n catalog entry; using English fallback.")
|
|
164
|
+
return format_message(reference)
|
|
165
|
+
return translated
|
|
166
|
+
|
|
167
|
+
def _build_bundle(self, locale_name: str) -> _CatalogBundle:
|
|
168
|
+
translations = load_catalog(locale_name, catalog_root=self._catalog_root)
|
|
169
|
+
return _CatalogBundle(
|
|
170
|
+
locale_name=locale_name,
|
|
171
|
+
translations=translations,
|
|
172
|
+
validate_template=_new_template_validator(),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _new_template_validator() -> _TemplateValidator:
|
|
177
|
+
@cache
|
|
178
|
+
def validate(template: str, multiline: bool) -> frozenset[str] | None:
|
|
179
|
+
try:
|
|
180
|
+
names = validate_authored_template(template, multiline=multiline)
|
|
181
|
+
except TypeError, ValueError:
|
|
182
|
+
return None
|
|
183
|
+
if _formatting._is_lookup_id(template):
|
|
184
|
+
return None
|
|
185
|
+
return names
|
|
186
|
+
|
|
187
|
+
return validate
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Immutable locale-neutral message definitions and bound references."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from collections.abc import Iterable
|
|
10
|
+
from dataclasses import InitVar, dataclass
|
|
11
|
+
|
|
12
|
+
from chrys.foundation.i18n.formatting import (
|
|
13
|
+
format_template,
|
|
14
|
+
has_visible_content,
|
|
15
|
+
parse_placeholder_names,
|
|
16
|
+
sanitize_legacy_block,
|
|
17
|
+
sanitize_legacy_scalar,
|
|
18
|
+
validate_authored_template,
|
|
19
|
+
)
|
|
20
|
+
from chrys.foundation.platform.files import surrogate_safe_text
|
|
21
|
+
|
|
22
|
+
_CONSTRUCTION_TOKEN = object()
|
|
23
|
+
_MESSAGE_KEY_RE = re.compile(r"[a-z0-9_]+(?:\.[a-z0-9_]+)+\Z")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _UnsetCount:
|
|
27
|
+
"""Sentinel distinguishing an omitted ``count`` from an explicit ``None``."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
_UNSET_COUNT = _UnsetCount()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True, slots=True)
|
|
34
|
+
class DisplayPath:
|
|
35
|
+
"""A filesystem path explicitly selected for safe display conversion."""
|
|
36
|
+
|
|
37
|
+
value: str
|
|
38
|
+
|
|
39
|
+
def __init__(self, value: str | os.PathLike[str]) -> None:
|
|
40
|
+
raw_value = os.fspath(value)
|
|
41
|
+
if type(raw_value) is not str:
|
|
42
|
+
raise TypeError("DisplayPath requires a text path.")
|
|
43
|
+
object.__setattr__(self, "value", raw_value)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True, slots=True)
|
|
47
|
+
class DisplayBlock:
|
|
48
|
+
"""Verbatim display text whose LF characters must be preserved."""
|
|
49
|
+
|
|
50
|
+
value: str
|
|
51
|
+
|
|
52
|
+
def __post_init__(self) -> None:
|
|
53
|
+
if type(self.value) is not str:
|
|
54
|
+
raise TypeError("DisplayBlock requires a string.")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
type MessageScalar = str | int
|
|
58
|
+
type _DisplaySequenceItem = MessageScalar | DisplayPath
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(frozen=True, slots=True)
|
|
62
|
+
class DisplaySequence:
|
|
63
|
+
"""An immutable flat sequence rendered with a fixed comma separator."""
|
|
64
|
+
|
|
65
|
+
values: tuple[_DisplaySequenceItem, ...]
|
|
66
|
+
|
|
67
|
+
def __init__(self, values: Iterable[_DisplaySequenceItem] = ()) -> None:
|
|
68
|
+
if isinstance(values, (str, bytes)):
|
|
69
|
+
raise TypeError("DisplaySequence requires an iterable of elements, not text.")
|
|
70
|
+
normalized = tuple(values)
|
|
71
|
+
object.__setattr__(self, "values", normalized)
|
|
72
|
+
for value in normalized:
|
|
73
|
+
if not _is_sequence_item(value):
|
|
74
|
+
raise TypeError("DisplaySequence element has an unsupported type.")
|
|
75
|
+
if not has_visible_content(_render_sequence_item(value)):
|
|
76
|
+
raise ValueError("Every DisplaySequence element must have visible content.")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
type MessageArg = MessageScalar | DisplayPath | DisplaySequence | DisplayBlock
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
83
|
+
class MessageDef:
|
|
84
|
+
"""One immutable, extractable semantic message definition."""
|
|
85
|
+
|
|
86
|
+
_token: InitVar[object]
|
|
87
|
+
key: str
|
|
88
|
+
fallback: str
|
|
89
|
+
plural_fallback: str | None = None
|
|
90
|
+
multiline: bool = False
|
|
91
|
+
|
|
92
|
+
def __init_subclass__(cls, **kwargs: object) -> None:
|
|
93
|
+
raise TypeError("MessageDef cannot be subclassed.")
|
|
94
|
+
|
|
95
|
+
def __post_init__(self, _token: object) -> None:
|
|
96
|
+
if _token is not _CONSTRUCTION_TOKEN:
|
|
97
|
+
raise TypeError("MessageDef values must be constructed with msg().")
|
|
98
|
+
_validate_definition(self)
|
|
99
|
+
|
|
100
|
+
def bind(self, *, count: int | _UnsetCount | None = _UNSET_COUNT, **args: MessageArg) -> MessageRef:
|
|
101
|
+
"""Bind one occurrence's named arguments and optional plural count."""
|
|
102
|
+
if count is _UNSET_COUNT:
|
|
103
|
+
resolved_count = None
|
|
104
|
+
elif self.plural_fallback is None:
|
|
105
|
+
raise ValueError("count is forbidden for a singular message definition.")
|
|
106
|
+
elif type(count) is not int:
|
|
107
|
+
raise TypeError("count must be exactly int.")
|
|
108
|
+
else:
|
|
109
|
+
resolved_count = count
|
|
110
|
+
return MessageRef(
|
|
111
|
+
_token=_CONSTRUCTION_TOKEN,
|
|
112
|
+
definition=self,
|
|
113
|
+
args=tuple(sorted(args.items())),
|
|
114
|
+
count=resolved_count,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
119
|
+
class MessageRef:
|
|
120
|
+
"""One immutable occurrence of a semantic message definition."""
|
|
121
|
+
|
|
122
|
+
_token: InitVar[object]
|
|
123
|
+
definition: MessageDef
|
|
124
|
+
args: tuple[tuple[str, MessageArg], ...] = ()
|
|
125
|
+
count: int | None = None
|
|
126
|
+
|
|
127
|
+
def __init_subclass__(cls, **kwargs: object) -> None:
|
|
128
|
+
raise TypeError("MessageRef cannot be subclassed.")
|
|
129
|
+
|
|
130
|
+
def __post_init__(self, _token: object) -> None:
|
|
131
|
+
if _token is not _CONSTRUCTION_TOKEN:
|
|
132
|
+
raise TypeError("MessageRef values must be constructed with MessageDef.bind().")
|
|
133
|
+
_validate_reference(self)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def msg(
|
|
137
|
+
key: str,
|
|
138
|
+
*,
|
|
139
|
+
fallback: str,
|
|
140
|
+
plural_fallback: str | None = None,
|
|
141
|
+
multiline: bool = False,
|
|
142
|
+
) -> MessageDef:
|
|
143
|
+
"""Declare one extractable semantic message definition."""
|
|
144
|
+
return MessageDef(
|
|
145
|
+
_token=_CONSTRUCTION_TOKEN,
|
|
146
|
+
key=key,
|
|
147
|
+
fallback=fallback,
|
|
148
|
+
plural_fallback=plural_fallback,
|
|
149
|
+
multiline=multiline,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _validate_definition(definition: MessageDef) -> None:
|
|
154
|
+
if type(definition.key) is not str or not _MESSAGE_KEY_RE.fullmatch(definition.key):
|
|
155
|
+
raise ValueError("Message key must contain two or more lowercase dotted segments.")
|
|
156
|
+
if type(definition.multiline) is not bool:
|
|
157
|
+
raise TypeError("The multiline flag must be a bool.")
|
|
158
|
+
if type(definition.fallback) is not str:
|
|
159
|
+
raise TypeError("Message fallback must be a string.")
|
|
160
|
+
if definition.plural_fallback is not None and type(definition.plural_fallback) is not str:
|
|
161
|
+
raise TypeError("Message plural fallback must be a string or None.")
|
|
162
|
+
|
|
163
|
+
singular_names = validate_authored_template(definition.fallback, multiline=definition.multiline)
|
|
164
|
+
if not has_visible_content(definition.fallback):
|
|
165
|
+
raise ValueError("Message fallback must have visible content.")
|
|
166
|
+
|
|
167
|
+
if definition.plural_fallback is None:
|
|
168
|
+
if "count" in singular_names:
|
|
169
|
+
raise ValueError("The reserved count slot requires a plural fallback.")
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
plural_names = validate_authored_template(definition.plural_fallback, multiline=definition.multiline)
|
|
173
|
+
if not has_visible_content(definition.plural_fallback):
|
|
174
|
+
raise ValueError("Message plural fallback must have visible content.")
|
|
175
|
+
if singular_names - {"count"} != plural_names - {"count"}:
|
|
176
|
+
raise ValueError("Singular and plural fallbacks must share one argument schema.")
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _validate_reference(reference: MessageRef) -> None:
|
|
180
|
+
if type(reference.definition) is not MessageDef:
|
|
181
|
+
raise TypeError("MessageRef.definition must be a MessageDef.")
|
|
182
|
+
if type(reference.args) is not tuple:
|
|
183
|
+
raise TypeError("MessageRef.args must be an immutable tuple.")
|
|
184
|
+
|
|
185
|
+
names: list[str] = []
|
|
186
|
+
has_display_block = False
|
|
187
|
+
for item in reference.args:
|
|
188
|
+
if type(item) is not tuple or len(item) != 2:
|
|
189
|
+
raise TypeError("Every bound argument must be a name/value tuple.")
|
|
190
|
+
name, value = item
|
|
191
|
+
if type(name) is not str:
|
|
192
|
+
raise TypeError("Bound argument names must be strings.")
|
|
193
|
+
if name == "count":
|
|
194
|
+
raise ValueError("count is reserved and cannot appear in bound arguments.")
|
|
195
|
+
if not _is_message_arg(value):
|
|
196
|
+
raise TypeError(f"Message argument {name!r} has an unsupported type.")
|
|
197
|
+
names.append(name)
|
|
198
|
+
has_display_block = has_display_block or type(value) is DisplayBlock
|
|
199
|
+
if names != sorted(set(names)):
|
|
200
|
+
raise ValueError("Bound arguments must have unique names in deterministic order.")
|
|
201
|
+
|
|
202
|
+
definition = reference.definition
|
|
203
|
+
if definition.plural_fallback is None:
|
|
204
|
+
if reference.count is not None:
|
|
205
|
+
raise ValueError("count is forbidden for a singular message definition.")
|
|
206
|
+
elif type(reference.count) is not int:
|
|
207
|
+
if reference.count is None:
|
|
208
|
+
raise ValueError("count is required for a plural message definition.")
|
|
209
|
+
raise TypeError("count must be exactly int.")
|
|
210
|
+
if has_display_block and not definition.multiline:
|
|
211
|
+
raise ValueError("DisplayBlock arguments require a multiline message definition.")
|
|
212
|
+
|
|
213
|
+
expected_names = parse_placeholder_names(definition.fallback) - {"count"}
|
|
214
|
+
if set(names) != expected_names:
|
|
215
|
+
raise ValueError("Bound arguments do not match the message argument schema.")
|
|
216
|
+
|
|
217
|
+
fallback = definition.fallback if reference.count is None or reference.count == 1 else definition.plural_fallback
|
|
218
|
+
if fallback is None:
|
|
219
|
+
raise ValueError("A plural reference requires a plural fallback.")
|
|
220
|
+
rendered = format_template(fallback, _render_arguments(reference), multiline=definition.multiline)
|
|
221
|
+
if not has_visible_content(rendered):
|
|
222
|
+
raise ValueError("The formatted English message must have visible content.")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _is_sequence_item(value: object) -> bool:
|
|
226
|
+
return type(value) in {str, int, DisplayPath}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _is_message_arg(value: object) -> bool:
|
|
230
|
+
return type(value) in {str, int, DisplayPath, DisplaySequence, DisplayBlock}
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _int_display(value: int) -> str:
|
|
234
|
+
try:
|
|
235
|
+
return str(value)
|
|
236
|
+
except ValueError as error: # CPython's int-to-str digit-count limit
|
|
237
|
+
raise ValueError("Integer message arguments must be displayable in decimal form.") from error
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _render_sequence_item(value: _DisplaySequenceItem) -> str:
|
|
241
|
+
if type(value) is DisplayPath:
|
|
242
|
+
return sanitize_legacy_scalar(surrogate_safe_text(value.value))
|
|
243
|
+
if type(value) is int:
|
|
244
|
+
return sanitize_legacy_scalar(_int_display(value))
|
|
245
|
+
return sanitize_legacy_scalar(surrogate_safe_text(str(value)))
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _render_message_arg(value: MessageArg) -> str:
|
|
249
|
+
# Every textual branch neutralizes lone surrogates, not just DisplayPath:
|
|
250
|
+
# scalar and block arguments routinely carry filesystem-derived values
|
|
251
|
+
# (profile names, path lists), and a surrogate that reaches a strict
|
|
252
|
+
# encode crashes the render sink.
|
|
253
|
+
if type(value) is DisplayPath:
|
|
254
|
+
return sanitize_legacy_scalar(surrogate_safe_text(value.value))
|
|
255
|
+
if type(value) is DisplaySequence:
|
|
256
|
+
return ", ".join(_render_sequence_item(element) for element in value.values)
|
|
257
|
+
if type(value) is DisplayBlock:
|
|
258
|
+
return sanitize_legacy_block(surrogate_safe_text(value.value))
|
|
259
|
+
if type(value) is int:
|
|
260
|
+
return sanitize_legacy_scalar(_int_display(value))
|
|
261
|
+
return sanitize_legacy_scalar(surrogate_safe_text(str(value)))
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _render_arguments(reference: MessageRef) -> dict[str, str]:
|
|
265
|
+
rendered = {name: _render_message_arg(value) for name, value in reference.args}
|
|
266
|
+
if reference.count is not None:
|
|
267
|
+
rendered["count"] = _int_display(reference.count)
|
|
268
|
+
return rendered
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Normalize rich tool results into display text and image content."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from collections.abc import Mapping
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from chrys.foundation.text.images import is_image_media_type
|
|
12
|
+
from chrys.foundation.text.model_json import model_json
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Marker prefix used by chrys to tag tool results as failures. TUI
|
|
18
|
+
# renderers check ``result.startswith(_ERROR_PREFIX)`` to apply error
|
|
19
|
+
# styling, and the LLM treats it as an error signal.
|
|
20
|
+
_ERROR_PREFIX = "Error: "
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _render_attr_value(val: Any) -> str:
|
|
24
|
+
"""Render a Content text-bearing attribute value to a string.
|
|
25
|
+
|
|
26
|
+
The text-bearing slots (``text``/``result``/``output``/``message``)
|
|
27
|
+
are typed ``Any`` on ``Content`` and in practice can hold non-string
|
|
28
|
+
values:
|
|
29
|
+
|
|
30
|
+
* ``Content.from_mcp_server_tool_result(output=...)`` accepts a
|
|
31
|
+
``list[Content]`` (the Anthropic provider builds these for
|
|
32
|
+
``mcp_tool_result`` blocks from Anthropic-managed MCP servers).
|
|
33
|
+
* Custom tools / providers may set ``result`` or ``output`` to a
|
|
34
|
+
``dict`` (e.g. structured JSON returned from an MCP server) or
|
|
35
|
+
another nested container.
|
|
36
|
+
|
|
37
|
+
Naively calling ``str(val)`` on these renders unusable object reprs
|
|
38
|
+
because ``Content`` does not override ``__repr__``. Instead:
|
|
39
|
+
|
|
40
|
+
* ``list``/``tuple`` -> recurse into :func:`extract_result_text` so
|
|
41
|
+
Content items inside the list are properly unwrapped.
|
|
42
|
+
* ``Mapping`` -> JSON-dump (preserves ``{"code": 500, "body": ...}``
|
|
43
|
+
style structured error payloads as readable JSON).
|
|
44
|
+
* everything else -> ``str(val)`` (numbers, bools, plain objects).
|
|
45
|
+
"""
|
|
46
|
+
if isinstance(val, str):
|
|
47
|
+
return val
|
|
48
|
+
if isinstance(val, (list, tuple)):
|
|
49
|
+
return extract_result_text(list(val))
|
|
50
|
+
if isinstance(val, Mapping):
|
|
51
|
+
try:
|
|
52
|
+
return model_json(val, default=str)
|
|
53
|
+
except TypeError, ValueError:
|
|
54
|
+
return str(val)
|
|
55
|
+
return str(val)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _content_to_text(item: Any) -> str:
|
|
59
|
+
"""Render a single ``Content``-like item to a string.
|
|
60
|
+
|
|
61
|
+
Tries the known text-bearing attributes in order (``text`` for text
|
|
62
|
+
items, ``result`` for function_result, ``output`` for
|
|
63
|
+
mcp_server_tool_result, ``message`` for error). For data/uri items
|
|
64
|
+
(images, audio, embedded blobs) returns a ``[<media_type>: <uri...>]``
|
|
65
|
+
placeholder so the LLM still sees something meaningful instead of a
|
|
66
|
+
bare object repr.
|
|
67
|
+
|
|
68
|
+
If the item has none of those attributes (e.g. an unexpected
|
|
69
|
+
function_call / approval_request Content showing up where a result
|
|
70
|
+
was expected), logs a WARNING and returns an ``"Error: ..."`` string
|
|
71
|
+
so the failure is surfaced both in logs and to the LLM/TUI rather
|
|
72
|
+
than masquerading as a successful structured result.
|
|
73
|
+
"""
|
|
74
|
+
if isinstance(item, str):
|
|
75
|
+
return item
|
|
76
|
+
if isinstance(item, Mapping):
|
|
77
|
+
return _render_attr_value(item)
|
|
78
|
+
# The first text-bearing attribute that is *present and non-None* wins,
|
|
79
|
+
# even if its value is the empty string: an empty text item should
|
|
80
|
+
# render as ``""`` (filtered upstream), not fall through to the
|
|
81
|
+
# structural-fields dump and emit ``{"type": "text", ...}``.
|
|
82
|
+
for attr in ("text", "result", "output", "message"):
|
|
83
|
+
val = getattr(item, attr, None)
|
|
84
|
+
if val is None:
|
|
85
|
+
continue
|
|
86
|
+
return _render_attr_value(val)
|
|
87
|
+
uri = getattr(item, "uri", None)
|
|
88
|
+
if uri:
|
|
89
|
+
media_type = getattr(item, "media_type", None) or "binary"
|
|
90
|
+
if _is_image_data_uri(media_type, uri):
|
|
91
|
+
return f"[{media_type} image]"
|
|
92
|
+
snippet = uri if len(uri) <= 120 else uri[:117] + "..."
|
|
93
|
+
return f"[{media_type}: {snippet}]"
|
|
94
|
+
# Unrecognized shape: every documented success path produces a
|
|
95
|
+
# Content with at least one of text/result/output/message/uri.
|
|
96
|
+
# Hitting this branch means either a framework Content schema drift
|
|
97
|
+
# or a misrouted call/state container ending up in a result list.
|
|
98
|
+
# Treat it as an error: log a warning and emit a clearly tagged
|
|
99
|
+
# diagnostic string so the LLM doesn't read raw JSON as success.
|
|
100
|
+
if hasattr(item, "__dict__"):
|
|
101
|
+
try:
|
|
102
|
+
d = {k: v for k, v in vars(item).items() if v not in (None, "") and not k.startswith("_")}
|
|
103
|
+
except TypeError:
|
|
104
|
+
d = {}
|
|
105
|
+
if not d:
|
|
106
|
+
# Object truly carries nothing: render as empty (filtered upstream).
|
|
107
|
+
return ""
|
|
108
|
+
type_hint = d.get("type", type(item).__name__)
|
|
109
|
+
logger.warning(
|
|
110
|
+
"Unrecognized tool result Content (type=%r); rendering as fallback. Fields: %s",
|
|
111
|
+
type_hint,
|
|
112
|
+
{k: _summarize_value(v) for k, v in d.items()},
|
|
113
|
+
)
|
|
114
|
+
return (
|
|
115
|
+
f"{_ERROR_PREFIX}unrecognized tool result content (type={type_hint}); fields: {model_json(d, default=str)}"
|
|
116
|
+
)
|
|
117
|
+
return str(item)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def extract_result_text(result: Any) -> str:
|
|
121
|
+
"""Extract displayable text from a tool invocation result.
|
|
122
|
+
|
|
123
|
+
Since rc5, ``FunctionTool.invoke()`` returns ``list[Content]`` instead
|
|
124
|
+
of a plain string. This walks the list and extracts text from each
|
|
125
|
+
Content item via :func:`_content_to_text`. When a Content item is
|
|
126
|
+
not understood, an unstructured fallback is logged at DEBUG so the
|
|
127
|
+
raw shape is recoverable from logs without crashing the tool result.
|
|
128
|
+
"""
|
|
129
|
+
if result is None:
|
|
130
|
+
return ""
|
|
131
|
+
# Guard against dangling coroutines left by cancelled tool invocations.
|
|
132
|
+
# FunctionMiddlewarePipeline can leave context.result holding the handler
|
|
133
|
+
# coroutine if cancellation interrupts its await. Close it rather than
|
|
134
|
+
# rendering a coroutine object as the tool's result.
|
|
135
|
+
import inspect
|
|
136
|
+
|
|
137
|
+
if inspect.isawaitable(result):
|
|
138
|
+
close = getattr(result, "close", None)
|
|
139
|
+
if close is not None:
|
|
140
|
+
close()
|
|
141
|
+
return ""
|
|
142
|
+
if isinstance(result, str):
|
|
143
|
+
return result
|
|
144
|
+
if isinstance(result, list):
|
|
145
|
+
if logger.isEnabledFor(logging.DEBUG):
|
|
146
|
+
logger.debug(
|
|
147
|
+
"Tool result list: %d item(s); types=%s; shapes=%s",
|
|
148
|
+
len(result),
|
|
149
|
+
[getattr(item, "type", type(item).__name__) for item in result],
|
|
150
|
+
[_summarize_item_shape(item) for item in result],
|
|
151
|
+
)
|
|
152
|
+
rendered = [_content_to_text(item) for item in result]
|
|
153
|
+
parts = [p for p in rendered if p]
|
|
154
|
+
if not parts:
|
|
155
|
+
return ""
|
|
156
|
+
# If any item triggered the unrecognized-content fallback, the
|
|
157
|
+
# whole result must surface as an error so the TUI styling and
|
|
158
|
+
# the chrys "Error: ..." convention apply to the joined string.
|
|
159
|
+
any_error = any(p.startswith(_ERROR_PREFIX) for p in parts)
|
|
160
|
+
joined = "\n".join(parts)
|
|
161
|
+
if any_error and not joined.startswith(_ERROR_PREFIX):
|
|
162
|
+
joined = _ERROR_PREFIX + joined
|
|
163
|
+
return joined
|
|
164
|
+
return _content_to_text(result)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def extract_result_images(result: Any) -> list[Any]:
|
|
168
|
+
"""Extract image Content-like items from a tool invocation result."""
|
|
169
|
+
if result is None or isinstance(result, str):
|
|
170
|
+
return []
|
|
171
|
+
if isinstance(result, list):
|
|
172
|
+
images: list[Any] = []
|
|
173
|
+
for item in result:
|
|
174
|
+
images.extend(extract_result_images(item))
|
|
175
|
+
return images
|
|
176
|
+
item_type = getattr(result, "type", None)
|
|
177
|
+
if item_type == "function_result":
|
|
178
|
+
items = getattr(result, "items", None)
|
|
179
|
+
return extract_result_images(items) if isinstance(items, list) else []
|
|
180
|
+
if item_type in ("data", "uri"):
|
|
181
|
+
media_type = getattr(result, "media_type", None)
|
|
182
|
+
properties = getattr(result, "additional_properties", None)
|
|
183
|
+
property_media_type = properties.get("media_type") if isinstance(properties, Mapping) else None
|
|
184
|
+
if is_image_media_type(media_type) or is_image_media_type(property_media_type):
|
|
185
|
+
return [result]
|
|
186
|
+
return []
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _is_image_data_uri(media_type: Any, uri: Any) -> bool:
|
|
190
|
+
return (
|
|
191
|
+
isinstance(media_type, str)
|
|
192
|
+
and media_type.lower().startswith("image/")
|
|
193
|
+
and isinstance(uri, str)
|
|
194
|
+
and uri.startswith("data:")
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
_DEBUG_STR_PREVIEW_CHARS = 80
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _summarize_value(v: Any) -> Any:
|
|
202
|
+
"""Render a single value as a debug-log-safe summary.
|
|
203
|
+
|
|
204
|
+
Long strings become ``<str len=N preview='...'>`` (only the first
|
|
205
|
+
``_DEBUG_STR_PREVIEW_CHARS`` chars previewed, via ``repr`` so any
|
|
206
|
+
binary/escape sequences stay quoted). Bytes and containers become
|
|
207
|
+
``<typename len=N>`` (no contents). Numbers/bools pass through.
|
|
208
|
+
Other objects become ``<typename>``.
|
|
209
|
+
"""
|
|
210
|
+
if isinstance(v, str):
|
|
211
|
+
if len(v) <= _DEBUG_STR_PREVIEW_CHARS:
|
|
212
|
+
return v
|
|
213
|
+
return f"<str len={len(v)} preview={v[:_DEBUG_STR_PREVIEW_CHARS]!r}>"
|
|
214
|
+
if isinstance(v, (bytes, bytearray, list, tuple, dict, set)):
|
|
215
|
+
return f"<{type(v).__name__} len={len(v)}>"
|
|
216
|
+
if isinstance(v, (int, float, bool)):
|
|
217
|
+
return v
|
|
218
|
+
return f"<{type(v).__name__}>"
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _summarize_item_shape(item: Any) -> Any:
|
|
222
|
+
"""Render a result-list item as a debug-log-safe shape descriptor.
|
|
223
|
+
|
|
224
|
+
For objects with ``__dict__`` (e.g. ``Content``):
|
|
225
|
+
returns a dict mapping field name -> :func:`_summarize_value` of the
|
|
226
|
+
value. For plain values (``str``, ``bytes``, primitives, etc.):
|
|
227
|
+
returns the same summary directly. Either way, large payloads:
|
|
228
|
+
base64 ``data:`` URIs, blob contents, big strings: never appear
|
|
229
|
+
verbatim in the DEBUG log.
|
|
230
|
+
"""
|
|
231
|
+
if not hasattr(item, "__dict__"):
|
|
232
|
+
return _summarize_value(item)
|
|
233
|
+
try:
|
|
234
|
+
fields = {k: v for k, v in vars(item).items() if v not in (None, "") and not k.startswith("_")}
|
|
235
|
+
except TypeError:
|
|
236
|
+
return _summarize_value(item)
|
|
237
|
+
return {k: _summarize_value(v) for k, v in fields.items()}
|