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,476 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Shared live MCP connection cache.
|
|
4
|
+
|
|
5
|
+
The cache stores successful, connected Chrys MCPTool instances and hands each
|
|
6
|
+
consumer fresh ``FunctionTool`` wrappers. Sharing the live
|
|
7
|
+
transport avoids repeated MCP connect/list latency across agent rebuilds while
|
|
8
|
+
keeping wrapper-level mutable state, such as approval mode counters, isolated
|
|
9
|
+
per parent or sub-agent consumer.
|
|
10
|
+
|
|
11
|
+
Identical parent/sub-agent MCP configs intentionally share one MCP session.
|
|
12
|
+
Stateful servers may therefore observe interleaved requests from multiple
|
|
13
|
+
agents; add a per-server opt-out only if a real server needs isolation.
|
|
14
|
+
The likely shape of that opt-out is a profile flag such as
|
|
15
|
+
``share_session: false`` on ``MCPServerConfig``. When adding it, include an
|
|
16
|
+
agent/session/share-boundary component in the cache key for those configs so
|
|
17
|
+
they still benefit from caching inside the chosen boundary without sharing one
|
|
18
|
+
server-side client session across independent agents.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import asyncio
|
|
24
|
+
import contextlib
|
|
25
|
+
import hashlib
|
|
26
|
+
import inspect
|
|
27
|
+
import json
|
|
28
|
+
import logging
|
|
29
|
+
import os
|
|
30
|
+
from collections.abc import Sequence
|
|
31
|
+
from dataclasses import dataclass
|
|
32
|
+
from datetime import UTC, datetime
|
|
33
|
+
from functools import wraps
|
|
34
|
+
from pathlib import Path
|
|
35
|
+
from typing import TYPE_CHECKING, Any
|
|
36
|
+
|
|
37
|
+
from chrys.foundation.tool_call_context import get_tool_context, set_tool_context
|
|
38
|
+
from chrys.foundation.tool_kinds import KIND_MCP, get_tool_kind, set_tool_kind
|
|
39
|
+
from chrys.foundation.util.env_templates import resolve_env_template_mapping
|
|
40
|
+
from chrys.kernel import FunctionTool
|
|
41
|
+
from chrys.service.mcp import _connection
|
|
42
|
+
from chrys.service.mcp._stdio_transport import _inherited_stdio_environment
|
|
43
|
+
from chrys.service.mcp.errors import MCPConnectionError
|
|
44
|
+
from chrys.service.mcp.result_limits import _MCP_PROMPT_TOOL_KEY, truncate_mcp_result
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from chrys.service.mcp.owned import MCPTool
|
|
48
|
+
from chrys.service.profiles.agents.schema import MCPServerConfig
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
logger = logging.getLogger(__name__)
|
|
52
|
+
|
|
53
|
+
IDLE_TTL_SECONDS = 300
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class MCPConnectionLease:
|
|
58
|
+
"""A per-consumer lease on a cached MCP connection."""
|
|
59
|
+
|
|
60
|
+
key: str
|
|
61
|
+
server_name: str
|
|
62
|
+
config: MCPServerConfig
|
|
63
|
+
functions: list[FunctionTool]
|
|
64
|
+
mcp_tool: MCPTool
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class MCPConnectionEntry:
|
|
69
|
+
"""Internal cache entry for one canonical MCP server config."""
|
|
70
|
+
|
|
71
|
+
key: str
|
|
72
|
+
config: MCPServerConfig
|
|
73
|
+
mcp_tool: MCPTool | None
|
|
74
|
+
refcount: int
|
|
75
|
+
last_used: datetime
|
|
76
|
+
connect_task: asyncio.Task[MCPTool] | None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass(frozen=True)
|
|
80
|
+
class MCPEffectiveConfig:
|
|
81
|
+
"""Resolved MCP config values used for both keying and connecting."""
|
|
82
|
+
|
|
83
|
+
config: MCPServerConfig
|
|
84
|
+
key: str
|
|
85
|
+
stdio_env: dict[str, str] | None = None
|
|
86
|
+
resolved_stdio_cwd: str | None = None
|
|
87
|
+
http_headers: dict[str, str] | None = None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _stable_mapping(mapping: dict[str, str]) -> list[tuple[str, str]]:
|
|
91
|
+
"""Return a deterministic representation for JSON cache-key payloads."""
|
|
92
|
+
return sorted(mapping.items())
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _consume_task_exception(task: asyncio.Task[Any]) -> None:
|
|
96
|
+
"""Mark background connect-task exceptions retrieved if every waiter left."""
|
|
97
|
+
if task.cancelled():
|
|
98
|
+
return
|
|
99
|
+
with contextlib.suppress(Exception):
|
|
100
|
+
task.exception()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _resolved_stdio_env(config: MCPServerConfig) -> dict[str, str]:
|
|
104
|
+
return resolve_env_template_mapping(config.env, location=f"MCP server {config.name!r} env")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _resolved_http_headers(config: MCPServerConfig) -> dict[str, str]:
|
|
108
|
+
if not config.resolve_header_templates:
|
|
109
|
+
return dict(config.headers)
|
|
110
|
+
return resolve_env_template_mapping(config.headers, location=f"MCP server {config.name!r} headers")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def resolve_mcp_effective_config(config: MCPServerConfig, *, stdio_cwd: str | None = None) -> MCPEffectiveConfig:
|
|
114
|
+
"""Resolve the effective config used for keying and connection creation.
|
|
115
|
+
|
|
116
|
+
Stdio MCP child processes inherit the supplied session cwd and process
|
|
117
|
+
environment at spawn time, so both are part of the key.
|
|
118
|
+
|
|
119
|
+
The key is intentionally independent of parent/sub-agent identity today:
|
|
120
|
+
identical configs share one live MCP session. If a future
|
|
121
|
+
``share_session: false`` config option is added for stateful MCP servers,
|
|
122
|
+
add the relevant isolation boundary to this payload before hashing.
|
|
123
|
+
"""
|
|
124
|
+
payload: dict[str, Any] = {
|
|
125
|
+
"name": config.name,
|
|
126
|
+
"transport": config.transport,
|
|
127
|
+
"load_prompts": config.load_prompts,
|
|
128
|
+
"tool_name_prefix": config.tool_name_prefix,
|
|
129
|
+
"allowed_tools": None if config.allowed_tools is None else sorted(config.allowed_tools),
|
|
130
|
+
"request_timeout": config.request_timeout,
|
|
131
|
+
}
|
|
132
|
+
stdio_env: dict[str, str] | None = None
|
|
133
|
+
resolved_stdio_cwd: str | None = None
|
|
134
|
+
http_headers: dict[str, str] | None = None
|
|
135
|
+
if config.transport == "stdio":
|
|
136
|
+
stdio_env = _resolved_stdio_env(config)
|
|
137
|
+
child_env = _inherited_stdio_environment(stdio_env)
|
|
138
|
+
resolved_stdio_cwd = stdio_cwd or os.getcwd()
|
|
139
|
+
payload["stdio"] = {
|
|
140
|
+
"command": config.command,
|
|
141
|
+
"args": list(config.args),
|
|
142
|
+
"encoding": config.encoding,
|
|
143
|
+
"env": _stable_mapping(child_env),
|
|
144
|
+
"cwd": resolved_stdio_cwd,
|
|
145
|
+
}
|
|
146
|
+
stdio_env = child_env
|
|
147
|
+
elif config.transport == "http":
|
|
148
|
+
http_headers = _resolved_http_headers(config)
|
|
149
|
+
payload["http"] = {
|
|
150
|
+
"url": config.url,
|
|
151
|
+
"headers": _stable_mapping(http_headers),
|
|
152
|
+
"resolve_header_templates": config.resolve_header_templates,
|
|
153
|
+
"terminate_on_close": config.terminate_on_close,
|
|
154
|
+
"verify_ssl": config.verify_ssl,
|
|
155
|
+
"bypass_proxy": config.bypass_proxy,
|
|
156
|
+
}
|
|
157
|
+
else:
|
|
158
|
+
payload["unknown_transport"] = config.transport
|
|
159
|
+
key_payload = json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True)
|
|
160
|
+
key = hashlib.sha256(key_payload.encode("utf-8")).hexdigest()
|
|
161
|
+
return MCPEffectiveConfig(
|
|
162
|
+
config=config,
|
|
163
|
+
key=key,
|
|
164
|
+
stdio_env=stdio_env,
|
|
165
|
+
resolved_stdio_cwd=resolved_stdio_cwd,
|
|
166
|
+
http_headers=http_headers,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def mcp_config_cache_key(config: MCPServerConfig, *, stdio_cwd: str | None = None) -> str:
|
|
171
|
+
"""Build a canonical fingerprint for the effective MCP server config."""
|
|
172
|
+
return resolve_mcp_effective_config(config, stdio_cwd=stdio_cwd).key
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def clone_mcp_function_tool(
|
|
176
|
+
source: Any,
|
|
177
|
+
*,
|
|
178
|
+
result_cap: int | None = None,
|
|
179
|
+
spill_dir: Path | None = None,
|
|
180
|
+
) -> FunctionTool:
|
|
181
|
+
"""Return a fresh chrys FunctionTool wrapper for a cached MCP function.
|
|
182
|
+
|
|
183
|
+
Everything delivered outward goes through this clone so mutable invocation
|
|
184
|
+
state stays isolated per consumer.
|
|
185
|
+
"""
|
|
186
|
+
if not isinstance(source, FunctionTool):
|
|
187
|
+
raise TypeError(f"Cached MCP tool {source!r} is not a FunctionTool")
|
|
188
|
+
func = source.func
|
|
189
|
+
additional_properties = dict(source.additional_properties or {})
|
|
190
|
+
if result_cap is not None and result_cap > 0 and not additional_properties.get(_MCP_PROMPT_TOOL_KEY):
|
|
191
|
+
|
|
192
|
+
@wraps(func)
|
|
193
|
+
async def _bounded(*args: Any, **kwargs: Any) -> Any:
|
|
194
|
+
result = func(*args, **kwargs)
|
|
195
|
+
if inspect.isawaitable(result):
|
|
196
|
+
result = await result
|
|
197
|
+
return await truncate_mcp_result(result, result_cap, spill_dir)
|
|
198
|
+
|
|
199
|
+
clone_func = _bounded
|
|
200
|
+
else:
|
|
201
|
+
clone_func = func
|
|
202
|
+
clone = FunctionTool(
|
|
203
|
+
func=clone_func,
|
|
204
|
+
name=source.name,
|
|
205
|
+
description=source.description,
|
|
206
|
+
max_invocations=source.max_invocations,
|
|
207
|
+
max_invocation_exceptions=source.max_invocation_exceptions,
|
|
208
|
+
additional_properties=additional_properties,
|
|
209
|
+
input_model=source.parameters(),
|
|
210
|
+
result_parser=source.result_parser,
|
|
211
|
+
)
|
|
212
|
+
set_tool_kind(clone, get_tool_kind(source) or KIND_MCP)
|
|
213
|
+
# The additional_properties dict-copy above does not carry out-of-band
|
|
214
|
+
# attributes — re-apply the provenance context like the kind.
|
|
215
|
+
source_context = get_tool_context(source)
|
|
216
|
+
if source_context is not None:
|
|
217
|
+
set_tool_context(clone, source_context)
|
|
218
|
+
cached_schema = source._input_schema_cached
|
|
219
|
+
if cached_schema is not None:
|
|
220
|
+
clone._input_schema_cached = cached_schema
|
|
221
|
+
clone._cached_parameters = source._cached_parameters
|
|
222
|
+
return clone
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class MCPConnectionCache:
|
|
226
|
+
"""Ref-counted cache of live MCP server connections."""
|
|
227
|
+
|
|
228
|
+
def __init__(self, *, idle_ttl_seconds: float = IDLE_TTL_SECONDS) -> None:
|
|
229
|
+
self._idle_ttl_seconds = idle_ttl_seconds
|
|
230
|
+
self._entries: dict[str, MCPConnectionEntry] = {}
|
|
231
|
+
self._lock = asyncio.Lock()
|
|
232
|
+
self._closed = False
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def closed(self) -> bool:
|
|
236
|
+
"""Whether ``close_all()`` has permanently closed this cache."""
|
|
237
|
+
return self._closed
|
|
238
|
+
|
|
239
|
+
async def acquire(self, config: MCPServerConfig, *, stdio_cwd: str | None = None) -> MCPConnectionLease:
|
|
240
|
+
"""Acquire a lease for ``config``, connecting once per cache key."""
|
|
241
|
+
try:
|
|
242
|
+
effective = resolve_mcp_effective_config(config, stdio_cwd=stdio_cwd)
|
|
243
|
+
except Exception as exc:
|
|
244
|
+
raise self._connection_error(config, exc) from exc
|
|
245
|
+
key = effective.key
|
|
246
|
+
|
|
247
|
+
lease: MCPConnectionLease | None = None
|
|
248
|
+
task: asyncio.Task[MCPTool] | None = None
|
|
249
|
+
async with self._lock:
|
|
250
|
+
if self._closed:
|
|
251
|
+
raise RuntimeError("MCP connection cache is closed")
|
|
252
|
+
stale_tools = self._collect_idle_locked(datetime.now(UTC), self._idle_ttl_seconds)
|
|
253
|
+
|
|
254
|
+
await self._close_untracked_tools(stale_tools)
|
|
255
|
+
|
|
256
|
+
async with self._lock:
|
|
257
|
+
if self._closed:
|
|
258
|
+
raise RuntimeError("MCP connection cache is closed")
|
|
259
|
+
entry = self._entries.get(key)
|
|
260
|
+
if entry is not None and entry.mcp_tool is not None:
|
|
261
|
+
lease = self._lease_from_entry(entry)
|
|
262
|
+
entry.refcount += 1
|
|
263
|
+
else:
|
|
264
|
+
if entry is None:
|
|
265
|
+
entry = MCPConnectionEntry(
|
|
266
|
+
key=key,
|
|
267
|
+
config=config,
|
|
268
|
+
mcp_tool=None,
|
|
269
|
+
refcount=0,
|
|
270
|
+
last_used=datetime.now(UTC),
|
|
271
|
+
connect_task=None,
|
|
272
|
+
)
|
|
273
|
+
self._entries[key] = entry
|
|
274
|
+
if entry.connect_task is None:
|
|
275
|
+
entry.connect_task = asyncio.create_task(self._connect_and_store(key, effective))
|
|
276
|
+
entry.connect_task.add_done_callback(_consume_task_exception)
|
|
277
|
+
task = entry.connect_task
|
|
278
|
+
|
|
279
|
+
if lease is not None:
|
|
280
|
+
return lease
|
|
281
|
+
if task is None:
|
|
282
|
+
raise RuntimeError(f"MCP server {config.name!r} did not start connecting")
|
|
283
|
+
await asyncio.shield(task)
|
|
284
|
+
|
|
285
|
+
async with self._lock:
|
|
286
|
+
if self._closed:
|
|
287
|
+
raise RuntimeError("MCP connection cache is closed")
|
|
288
|
+
entry = self._entries.get(key)
|
|
289
|
+
if entry is None or entry.mcp_tool is None:
|
|
290
|
+
raise RuntimeError(f"MCP server {config.name!r} did not register after connect")
|
|
291
|
+
lease = self._lease_from_entry(entry)
|
|
292
|
+
entry.refcount += 1
|
|
293
|
+
return lease
|
|
294
|
+
|
|
295
|
+
async def release(self, lease: MCPConnectionLease) -> None:
|
|
296
|
+
"""Release a previously acquired lease."""
|
|
297
|
+
stale_tools: list[MCPTool] = []
|
|
298
|
+
async with self._lock:
|
|
299
|
+
entry = self._entries.get(lease.key)
|
|
300
|
+
if entry is not None and entry.refcount > 0:
|
|
301
|
+
entry.refcount -= 1
|
|
302
|
+
if entry.refcount == 0:
|
|
303
|
+
entry.last_used = datetime.now(UTC)
|
|
304
|
+
stale_tools = self._collect_idle_locked(datetime.now(UTC), self._idle_ttl_seconds)
|
|
305
|
+
await self._close_untracked_tools(stale_tools)
|
|
306
|
+
|
|
307
|
+
async def prune_idle(self, *, max_idle_seconds: float | None = None) -> None:
|
|
308
|
+
"""Close idle entries that have exceeded ``max_idle_seconds``.
|
|
309
|
+
|
|
310
|
+
This is intentionally lazy. There is no background task; callers prune
|
|
311
|
+
on acquire/release, and private adapter caches can pass ``0`` to close
|
|
312
|
+
released entries immediately.
|
|
313
|
+
"""
|
|
314
|
+
ttl = self._idle_ttl_seconds if max_idle_seconds is None else max_idle_seconds
|
|
315
|
+
async with self._lock:
|
|
316
|
+
stale_tools = self._collect_idle_locked(datetime.now(UTC), ttl)
|
|
317
|
+
await self._close_untracked_tools(stale_tools)
|
|
318
|
+
|
|
319
|
+
async def close_all(self) -> None:
|
|
320
|
+
"""Close every live MCP connection and reject future acquires."""
|
|
321
|
+
async with self._lock:
|
|
322
|
+
self._closed = True
|
|
323
|
+
entries = list(self._entries.values())
|
|
324
|
+
self._entries.clear()
|
|
325
|
+
|
|
326
|
+
tasks = [entry.connect_task for entry in entries if entry.connect_task is not None]
|
|
327
|
+
tools = [entry.mcp_tool for entry in entries if entry.mcp_tool is not None]
|
|
328
|
+
for task in tasks:
|
|
329
|
+
if not task.done():
|
|
330
|
+
task.cancel()
|
|
331
|
+
if tasks:
|
|
332
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
333
|
+
await self._close_untracked_tools(tools)
|
|
334
|
+
|
|
335
|
+
async def _connect_and_store(self, key: str, effective: MCPEffectiveConfig) -> MCPTool:
|
|
336
|
+
"""Connect an MCP server and publish the result into the cache entry."""
|
|
337
|
+
config = effective.config
|
|
338
|
+
mcp_tool: MCPTool | None = None
|
|
339
|
+
stored = False
|
|
340
|
+
try:
|
|
341
|
+
mcp_tool = await self._open_mcp_tool(effective)
|
|
342
|
+
for tool in list(mcp_tool.functions):
|
|
343
|
+
set_tool_kind(tool, KIND_MCP)
|
|
344
|
+
try:
|
|
345
|
+
async with self._lock:
|
|
346
|
+
entry = self._entries.get(key)
|
|
347
|
+
current_task = asyncio.current_task()
|
|
348
|
+
if self._closed or entry is None or entry.connect_task is not current_task:
|
|
349
|
+
return mcp_tool
|
|
350
|
+
entry.mcp_tool = mcp_tool
|
|
351
|
+
entry.connect_task = None
|
|
352
|
+
entry.last_used = datetime.now(UTC)
|
|
353
|
+
stored = True
|
|
354
|
+
return mcp_tool
|
|
355
|
+
finally:
|
|
356
|
+
if not stored:
|
|
357
|
+
await self._close_tool(config.name, mcp_tool)
|
|
358
|
+
except asyncio.CancelledError:
|
|
359
|
+
if mcp_tool is not None and not stored:
|
|
360
|
+
await self._close_tool(config.name, mcp_tool)
|
|
361
|
+
raise
|
|
362
|
+
except Exception:
|
|
363
|
+
async with self._lock:
|
|
364
|
+
entry = self._entries.get(key)
|
|
365
|
+
if entry is not None and entry.connect_task is asyncio.current_task():
|
|
366
|
+
self._entries.pop(key, None)
|
|
367
|
+
raise
|
|
368
|
+
|
|
369
|
+
async def _open_mcp_tool(self, effective: MCPEffectiveConfig) -> MCPTool:
|
|
370
|
+
"""Create and enter one live MCPTool, wrapping failures like MCPAdapter."""
|
|
371
|
+
config = effective.config
|
|
372
|
+
mcp_tool: MCPTool | None = None
|
|
373
|
+
try:
|
|
374
|
+
mcp_tool = _connection._create_tool_with_timeout_floor(
|
|
375
|
+
config,
|
|
376
|
+
_connection.DEFAULT_CONNECT_TIMEOUT_SECONDS,
|
|
377
|
+
resolved_stdio_env=effective.stdio_env,
|
|
378
|
+
stdio_cwd=effective.resolved_stdio_cwd,
|
|
379
|
+
resolved_http_headers=effective.http_headers,
|
|
380
|
+
)
|
|
381
|
+
await mcp_tool.__aenter__()
|
|
382
|
+
except asyncio.CancelledError:
|
|
383
|
+
if mcp_tool is not None:
|
|
384
|
+
with contextlib.suppress(Exception):
|
|
385
|
+
await mcp_tool.__aexit__(None, None, None)
|
|
386
|
+
raise
|
|
387
|
+
except MCPConnectionError:
|
|
388
|
+
if mcp_tool is not None:
|
|
389
|
+
with contextlib.suppress(Exception):
|
|
390
|
+
await mcp_tool.__aexit__(None, None, None)
|
|
391
|
+
raise
|
|
392
|
+
except Exception as exc:
|
|
393
|
+
if mcp_tool is not None:
|
|
394
|
+
with contextlib.suppress(Exception):
|
|
395
|
+
await mcp_tool.__aexit__(None, None, None)
|
|
396
|
+
diagnostics = _connection._stdio_failure_diagnostics_from(mcp_tool)
|
|
397
|
+
cause: BaseException = exc
|
|
398
|
+
if _connection._is_timeout_cause(exc):
|
|
399
|
+
timeout = (
|
|
400
|
+
mcp_tool.request_timeout if mcp_tool is not None else _connection.DEFAULT_CONNECT_TIMEOUT_SECONDS
|
|
401
|
+
)
|
|
402
|
+
cause = TimeoutError(f"connection did not complete within {timeout}s (server may not be speaking MCP)")
|
|
403
|
+
raise MCPConnectionError(
|
|
404
|
+
config.name,
|
|
405
|
+
config.transport,
|
|
406
|
+
cause,
|
|
407
|
+
banner_lines=_connection._banner_lines_from(mcp_tool),
|
|
408
|
+
stderr_tail=diagnostics.stderr_tail,
|
|
409
|
+
stderr_dropped_bytes=diagnostics.stderr_dropped_bytes,
|
|
410
|
+
process_exit_code=diagnostics.process_exit_code,
|
|
411
|
+
resolved_executable=diagnostics.resolved_executable,
|
|
412
|
+
effective_cwd=diagnostics.effective_cwd,
|
|
413
|
+
) from exc
|
|
414
|
+
if mcp_tool is None:
|
|
415
|
+
raise MCPConnectionError(config.name, config.transport)
|
|
416
|
+
return mcp_tool
|
|
417
|
+
|
|
418
|
+
def _lease_from_entry(self, entry: MCPConnectionEntry) -> MCPConnectionLease:
|
|
419
|
+
if entry.mcp_tool is None:
|
|
420
|
+
raise RuntimeError(f"MCP server {entry.config.name!r} is not connected")
|
|
421
|
+
functions = [clone_mcp_function_tool(tool) for tool in entry.mcp_tool.functions]
|
|
422
|
+
return MCPConnectionLease(
|
|
423
|
+
key=entry.key,
|
|
424
|
+
server_name=entry.config.name,
|
|
425
|
+
config=entry.config,
|
|
426
|
+
functions=functions,
|
|
427
|
+
mcp_tool=entry.mcp_tool,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
def _collect_idle_locked(self, now: datetime, max_idle_seconds: float) -> list[MCPTool]:
|
|
431
|
+
stale: list[MCPTool] = []
|
|
432
|
+
for key, entry in list(self._entries.items()):
|
|
433
|
+
if entry.refcount > 0 or entry.mcp_tool is None:
|
|
434
|
+
continue
|
|
435
|
+
idle_seconds = (now - entry.last_used).total_seconds()
|
|
436
|
+
if idle_seconds < max_idle_seconds:
|
|
437
|
+
continue
|
|
438
|
+
self._entries.pop(key, None)
|
|
439
|
+
stale.append(entry.mcp_tool)
|
|
440
|
+
return stale
|
|
441
|
+
|
|
442
|
+
async def _close_tools(self, tools: Sequence[MCPTool | None]) -> None:
|
|
443
|
+
if not tools:
|
|
444
|
+
return
|
|
445
|
+
await asyncio.gather(
|
|
446
|
+
*(self._close_tool(getattr(tool, "name", "<unknown>"), tool) for tool in tools if tool is not None),
|
|
447
|
+
return_exceptions=True,
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
async def _close_untracked_tools(self, tools: Sequence[MCPTool | None]) -> None:
|
|
451
|
+
"""Close tools that have already been removed from cache tracking.
|
|
452
|
+
|
|
453
|
+
Once entries are removed from ``_entries``, ``close_all()`` cannot find
|
|
454
|
+
them. Shield the close task so caller cancellation does not cancel the
|
|
455
|
+
actual transport cleanup, then wait for cleanup before re-raising.
|
|
456
|
+
"""
|
|
457
|
+
if not tools:
|
|
458
|
+
return
|
|
459
|
+
close_task = asyncio.create_task(self._close_tools(tools))
|
|
460
|
+
try:
|
|
461
|
+
await asyncio.shield(close_task)
|
|
462
|
+
except asyncio.CancelledError:
|
|
463
|
+
with contextlib.suppress(Exception):
|
|
464
|
+
await close_task
|
|
465
|
+
raise
|
|
466
|
+
|
|
467
|
+
async def _close_tool(self, name: str, tool: MCPTool) -> None:
|
|
468
|
+
try:
|
|
469
|
+
await tool.__aexit__(None, None, None)
|
|
470
|
+
except Exception:
|
|
471
|
+
logger.exception("Error disconnecting cached MCP server '%s'", name)
|
|
472
|
+
|
|
473
|
+
def _connection_error(self, config: MCPServerConfig, exc: Exception) -> Exception:
|
|
474
|
+
if isinstance(exc, MCPConnectionError):
|
|
475
|
+
return exc
|
|
476
|
+
return MCPConnectionError(config.name, config.transport, exc)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Media an MCP server sends as base64.
|
|
4
|
+
|
|
5
|
+
Data that does not decode becomes a placeholder text item in place of the
|
|
6
|
+
media, so the rest of the result still reaches the model.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import base64
|
|
12
|
+
import binascii
|
|
13
|
+
from typing import Final
|
|
14
|
+
|
|
15
|
+
INVALID_IMAGE_TEXT: Final = "[Image omitted: invalid base64 data.]"
|
|
16
|
+
INVALID_AUDIO_TEXT: Final = "[Audio omitted: invalid base64 data.]"
|
|
17
|
+
INVALID_RESOURCE_TEXT: Final = "[Resource omitted: invalid base64 data.]"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def decode_media_base64(value: str) -> bytes | None:
|
|
21
|
+
"""The bytes of *value*, bare base64 or a ``data:…;base64,`` URI; None when it is neither.
|
|
22
|
+
|
|
23
|
+
Whitespace in the payload is ignored: servers may send line-wrapped base64.
|
|
24
|
+
"""
|
|
25
|
+
if value.startswith("data:"):
|
|
26
|
+
header, separator, value = value.partition(",")
|
|
27
|
+
if not separator or not header.endswith(";base64"):
|
|
28
|
+
return None
|
|
29
|
+
try:
|
|
30
|
+
return base64.b64decode("".join(value.split()), validate=True)
|
|
31
|
+
except binascii.Error, ValueError:
|
|
32
|
+
return None
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""MCP adapter error types."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Collection, Mapping
|
|
8
|
+
|
|
9
|
+
from chrys.foundation.errors import clean_error_message
|
|
10
|
+
from chrys.service.mcp._stdio_transport import (
|
|
11
|
+
MAX_BANNER_LINE_CHARS,
|
|
12
|
+
MAX_STDIO_STDERR_BYTES_CAPTURED,
|
|
13
|
+
_clean_stdio_stderr,
|
|
14
|
+
_display_path,
|
|
15
|
+
_stderr_preview,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MCPConnectionError(RuntimeError):
|
|
20
|
+
"""Raised when an MCP server fails to connect, initialize, or list tools.
|
|
21
|
+
|
|
22
|
+
``banner_lines`` carries any non-JSON output the stdio child wrote to
|
|
23
|
+
its stdout before initialization (captured by ``tolerant_stdio_client``).
|
|
24
|
+
Surfaced in the error string so the user can see at a glance that a
|
|
25
|
+
server is emitting a banner instead of speaking JSON-RPC.
|
|
26
|
+
|
|
27
|
+
Stdio process failures may also carry a bounded ``stderr_tail``,
|
|
28
|
+
``process_exit_code``, ``resolved_executable`` and ``effective_cwd``.
|
|
29
|
+
Stderr is captured separately from stdout so server diagnostics can never
|
|
30
|
+
corrupt the JSON-RPC protocol stream; the message previews only the last
|
|
31
|
+
:data:`MAX_STDIO_STDERR_PREVIEW_LINES` lines of it.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
server_name: str,
|
|
37
|
+
transport: str,
|
|
38
|
+
cause: BaseException | None = None,
|
|
39
|
+
banner_lines: list[str] | None = None,
|
|
40
|
+
*,
|
|
41
|
+
failure_summary: str = "failed to connect",
|
|
42
|
+
stderr_tail: str = "",
|
|
43
|
+
stderr_dropped_bytes: int = 0,
|
|
44
|
+
process_exit_code: int | None = None,
|
|
45
|
+
resolved_executable: str = "",
|
|
46
|
+
effective_cwd: str = "",
|
|
47
|
+
) -> None:
|
|
48
|
+
self.server_name = server_name
|
|
49
|
+
self.transport = transport
|
|
50
|
+
self.cause = cause
|
|
51
|
+
# Truncate each line so a single very long banner row (e.g. a
|
|
52
|
+
# serialized stack trace) can't blow up the error message.
|
|
53
|
+
self.banner_lines: list[str] = (
|
|
54
|
+
[
|
|
55
|
+
(line[:MAX_BANNER_LINE_CHARS] + "…") if len(line) > MAX_BANNER_LINE_CHARS else line
|
|
56
|
+
for line in banner_lines
|
|
57
|
+
]
|
|
58
|
+
if banner_lines
|
|
59
|
+
else []
|
|
60
|
+
)
|
|
61
|
+
self.stderr_tail = _clean_stdio_stderr(stderr_tail)[-MAX_STDIO_STDERR_BYTES_CAPTURED:]
|
|
62
|
+
self.stderr_dropped_bytes = max(0, stderr_dropped_bytes)
|
|
63
|
+
self.process_exit_code = process_exit_code
|
|
64
|
+
self.resolved_executable = resolved_executable
|
|
65
|
+
self.effective_cwd = effective_cwd
|
|
66
|
+
detail = f": {clean_error_message(cause)}" if cause is not None else ""
|
|
67
|
+
message = f"MCP server {server_name!r} ({transport}) {failure_summary}{detail}"
|
|
68
|
+
context_lines = []
|
|
69
|
+
if self.resolved_executable:
|
|
70
|
+
context_lines.append(f"Executable: {_display_path(self.resolved_executable)}")
|
|
71
|
+
if self.effective_cwd:
|
|
72
|
+
context_lines.append(f"Working directory: {_display_path(self.effective_cwd)}")
|
|
73
|
+
if context_lines:
|
|
74
|
+
message = f"{message}\n\n" + "\n".join(context_lines)
|
|
75
|
+
if self.process_exit_code == 0:
|
|
76
|
+
message = f"{message}\n\nServer process exited normally (code 0) before completing the MCP handshake."
|
|
77
|
+
elif self.process_exit_code is not None:
|
|
78
|
+
message = f"{message}\n\nServer process exit code: {self.process_exit_code}."
|
|
79
|
+
if self.stderr_tail:
|
|
80
|
+
preview = _stderr_preview(self.stderr_tail, dropped_bytes=self.stderr_dropped_bytes)
|
|
81
|
+
message = f"{message}\n\n{preview}"
|
|
82
|
+
if self.banner_lines:
|
|
83
|
+
preview = "\n ".join(self.banner_lines)
|
|
84
|
+
message = f"{message}\n\nServer emitted non-JSON output before initialization:\n {preview}"
|
|
85
|
+
super().__init__(message)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class MCPToolConfigurationError(MCPConnectionError):
|
|
89
|
+
"""Base class for deterministic MCP tool-namespace configuration errors."""
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class MCPToolNameCollisionError(MCPToolConfigurationError):
|
|
93
|
+
"""Raised when a permitted MCP tool namespace is not globally unique."""
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
server_name: str,
|
|
98
|
+
transport: str,
|
|
99
|
+
*,
|
|
100
|
+
conflicting_names: Collection[str],
|
|
101
|
+
conflict_with: str,
|
|
102
|
+
guidance: str,
|
|
103
|
+
) -> None:
|
|
104
|
+
self.conflicting_names = tuple(sorted(set(conflicting_names)))
|
|
105
|
+
self.conflict_with = conflict_with
|
|
106
|
+
names = ", ".join(self.conflicting_names)
|
|
107
|
+
cause = ValueError(f"permitted tool name collision with {conflict_with}: {names}. {guidance}")
|
|
108
|
+
super().__init__(
|
|
109
|
+
server_name,
|
|
110
|
+
transport,
|
|
111
|
+
cause,
|
|
112
|
+
failure_summary="has invalid tool configuration",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class MCPToolNameAmbiguityError(MCPToolConfigurationError):
|
|
117
|
+
"""Raised when an ``allowed_tools``/``always_load`` name selects more than one tool."""
|
|
118
|
+
|
|
119
|
+
def __init__(
|
|
120
|
+
self,
|
|
121
|
+
server_name: str,
|
|
122
|
+
transport: str,
|
|
123
|
+
*,
|
|
124
|
+
matches_by_name: Mapping[str, Collection[tuple[str, str | None]]],
|
|
125
|
+
) -> None:
|
|
126
|
+
"""*matches_by_name* maps each ambiguous entry to ``(original name, name selecting only that tool)``
|
|
127
|
+
pairs, one per tool it matches; the second item is None when no name selects that tool alone.
|
|
128
|
+
"""
|
|
129
|
+
self.matches_by_name = {name: tuple(sorted(matches)) for name, matches in sorted(matches_by_name.items())}
|
|
130
|
+
details = "; ".join(
|
|
131
|
+
f"'{name}' matches " + ", ".join(_describe_ambiguous_match(original, sole) for original, sole in matches)
|
|
132
|
+
for name, matches in self.matches_by_name.items()
|
|
133
|
+
)
|
|
134
|
+
message = f"a configured tool name selects more than one tool: {details}."
|
|
135
|
+
if any(sole is None for matches in self.matches_by_name.values() for _original, sole in matches):
|
|
136
|
+
message += " Configure a different Tool Name Prefix to tell apart a tool that no name selects alone."
|
|
137
|
+
cause = ValueError(message)
|
|
138
|
+
super().__init__(
|
|
139
|
+
server_name,
|
|
140
|
+
transport,
|
|
141
|
+
cause,
|
|
142
|
+
failure_summary="has invalid tool configuration",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _describe_ambiguous_match(original: str, sole: str | None) -> str:
|
|
147
|
+
if sole is None:
|
|
148
|
+
return f"the server's '{original}' (no name selects only it)"
|
|
149
|
+
return f"the server's '{original}' (write '{sole}' to select only it)"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class MCPToolNameValidationError(MCPToolConfigurationError):
|
|
153
|
+
"""Raised when an exposed MCP tool name is not accepted by model providers."""
|
|
154
|
+
|
|
155
|
+
def __init__(
|
|
156
|
+
self,
|
|
157
|
+
server_name: str,
|
|
158
|
+
transport: str,
|
|
159
|
+
*,
|
|
160
|
+
violations: Collection[str],
|
|
161
|
+
) -> None:
|
|
162
|
+
self.violations = tuple(sorted(set(violations)))
|
|
163
|
+
cause = ValueError("provider-incompatible MCP tool name: " + "; ".join(self.violations))
|
|
164
|
+
super().__init__(
|
|
165
|
+
server_name,
|
|
166
|
+
transport,
|
|
167
|
+
cause,
|
|
168
|
+
failure_summary="has invalid tool configuration",
|
|
169
|
+
)
|