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,894 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""The workflow shell around one agent-node activation.
|
|
4
|
+
|
|
5
|
+
One shell per activation: :meth:`WorkflowAgentShell.open` builds a private
|
|
6
|
+
kernel or ACP conversation for the node's agent and model binding, :meth:`run`
|
|
7
|
+
executes one pass per scheduler attempt, :meth:`abort` converges the in-flight
|
|
8
|
+
pass with a caller cause, and :meth:`close` unbinds and releases everything in
|
|
9
|
+
reverse. The shell is the third caller of the invoker contract after the main
|
|
10
|
+
turn and the sub-agent tool. Inside a pass a kernel node retries a failed
|
|
11
|
+
request as the chat agent does, in place on the wire or as a whole run under
|
|
12
|
+
service-side storage; across passes the scheduler decides from the
|
|
13
|
+
:class:`FailureReport` each attempt yields, and the shell resumes what the
|
|
14
|
+
failed pass left: a kernel pass continues its repaired history, an ACP pass
|
|
15
|
+
starts a new session.
|
|
16
|
+
|
|
17
|
+
Every scheduler attempt publishes under its own origin, so a presentation
|
|
18
|
+
never folds one attempt's late facts into another.
|
|
19
|
+
|
|
20
|
+
Kernel nodes are built like the chat agent — builtin, sub-agent, MCP and skill
|
|
21
|
+
tools plus the profile's auto-loaded memory — and the ``ask_user`` tool is
|
|
22
|
+
dropped whenever the run is headless. No workflow surface shows a per-child
|
|
23
|
+
card, so a failed child ends at once instead of pausing; the shell routes the
|
|
24
|
+
engine's approval mode and the run's abort to the node's own sub-agents.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import asyncio
|
|
30
|
+
import logging
|
|
31
|
+
from collections.abc import Awaitable, Mapping
|
|
32
|
+
from contextvars import ContextVar
|
|
33
|
+
from dataclasses import dataclass, replace
|
|
34
|
+
from typing import TYPE_CHECKING, Any, Final, Literal
|
|
35
|
+
|
|
36
|
+
from chrys.foundation.errors import ErrorKind, classify_error, clean_error_message, is_retryable
|
|
37
|
+
from chrys.foundation.errors.display import display_fields
|
|
38
|
+
from chrys.foundation.events.types import (
|
|
39
|
+
InvocationMessage,
|
|
40
|
+
InvocationResumed,
|
|
41
|
+
InvocationRetryAttempt,
|
|
42
|
+
InvocationStarted,
|
|
43
|
+
)
|
|
44
|
+
from chrys.foundation.hosted_tools import HostedToolStatus
|
|
45
|
+
from chrys.foundation.models.invocations import InvocationOrigin
|
|
46
|
+
from chrys.foundation.trajectory.context import TRAJECTORY_CONTEXT_KWARG, TrajectoryContext, workflow_node_actor
|
|
47
|
+
from chrys.foundation.trajectory.ids import new_analytics_id
|
|
48
|
+
from chrys.foundation.trajectory.metadata import ensure_analytics_item_id
|
|
49
|
+
from chrys.foundation.util.once_close import finish_close
|
|
50
|
+
from chrys.kernel import AgentResponse, Message
|
|
51
|
+
from chrys.orchestration.invoker.acp import AcpConversation, AcpInvocationCounters
|
|
52
|
+
from chrys.orchestration.invoker.acp_protocol import AcpUpdateTranslator
|
|
53
|
+
from chrys.orchestration.invoker.attempts import drop_continuation_token, has_live_continuation_token
|
|
54
|
+
from chrys.orchestration.invoker.child_history import active_input_message
|
|
55
|
+
from chrys.orchestration.invoker.contracts import (
|
|
56
|
+
AbortCause,
|
|
57
|
+
Aborted,
|
|
58
|
+
ContinuationTicket,
|
|
59
|
+
Failed,
|
|
60
|
+
FailureCategory,
|
|
61
|
+
InvocationOutcome,
|
|
62
|
+
Ok,
|
|
63
|
+
OverlappingRun,
|
|
64
|
+
PreparedClosed,
|
|
65
|
+
RunIntent,
|
|
66
|
+
RunRequest,
|
|
67
|
+
StaleContinuation,
|
|
68
|
+
Unbind,
|
|
69
|
+
UnsupportedRequest,
|
|
70
|
+
)
|
|
71
|
+
from chrys.orchestration.invoker.evidence import InvocationEvidence
|
|
72
|
+
from chrys.orchestration.invoker.kernel import KernelConversation
|
|
73
|
+
from chrys.orchestration.invoker.origin import BoundEmitter
|
|
74
|
+
from chrys.orchestration.invoker.resources import Conversation, PassResources, PreparedAgent
|
|
75
|
+
from chrys.orchestration.workflows.agent_archive import CoalescedCheckpoint
|
|
76
|
+
from chrys.orchestration.workflows.agent_node_build import (
|
|
77
|
+
AcpNodeParts,
|
|
78
|
+
AgentNodeCallbacks,
|
|
79
|
+
AgentNodeResources,
|
|
80
|
+
KernelNodeParts,
|
|
81
|
+
build_acp_node,
|
|
82
|
+
build_kernel_node,
|
|
83
|
+
)
|
|
84
|
+
from chrys.service.agent_middleware.events.hosted_tools import FinalSegment
|
|
85
|
+
from chrys.service.agent_middleware.events.intermediate_text import IntermediateTextBuffer
|
|
86
|
+
from chrys.service.agent_middleware.response_validation import hosted_commits_from_error
|
|
87
|
+
from chrys.service.session.history import SessionHistoryManager, stamp_history_item_ids
|
|
88
|
+
from chrys.service.session.sub_agent_logs import SubAgentLogStats
|
|
89
|
+
from chrys.service.workflows.scheduler import ErrorClass, FailureReport
|
|
90
|
+
from chrys.service.workflows.store import WorkflowStorageFailed
|
|
91
|
+
|
|
92
|
+
if TYPE_CHECKING:
|
|
93
|
+
from chrys.foundation.retry import RetryAttemptInfo
|
|
94
|
+
from chrys.orchestration.workflows.agent_archive import AgentNodeArchive
|
|
95
|
+
from chrys.service.approval.policy import ApprovalMode
|
|
96
|
+
from chrys.service.workflows.admission import AgentBinding
|
|
97
|
+
|
|
98
|
+
logger = logging.getLogger(__name__)
|
|
99
|
+
|
|
100
|
+
# The shell whose pass the current task runs under; every task the kernel starts for a pass inherits it.
|
|
101
|
+
_PASS_SHELL: ContextVar[WorkflowAgentShell | None] = ContextVar("chrys.workflow.pass_shell", default=None)
|
|
102
|
+
|
|
103
|
+
ABORT_GRACE: Final = 10.0
|
|
104
|
+
"""Seconds a timed-out pass may take to converge after its abort before the run task is cancelled."""
|
|
105
|
+
_TERMINAL_CAUSES: Final = frozenset({AbortCause.USER_CANCEL, AbortCause.RUN_TERMINAL, AbortCause.OWNER_CLOSE})
|
|
106
|
+
# ACP failure categories a new session can overturn; the rest end the same way again.
|
|
107
|
+
_RETRYABLE_ACP_CATEGORIES: Final = frozenset({FailureCategory.TRANSPORT, FailureCategory.REMOTE_ERROR})
|
|
108
|
+
|
|
109
|
+
AttemptKind = Literal["completed", "failed", "cancelled"]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass(frozen=True, slots=True)
|
|
113
|
+
class AgentAttemptResult:
|
|
114
|
+
"""How one pass ended: ``completed`` with the response text, ``failed`` with a report, or ``cancelled``."""
|
|
115
|
+
|
|
116
|
+
kind: AttemptKind
|
|
117
|
+
text: str = ""
|
|
118
|
+
failure: FailureReport | None = None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class WorkflowAgentShell:
|
|
122
|
+
"""One agent activation: a private conversation, one pass per attempt, and the caller's abort latch.
|
|
123
|
+
|
|
124
|
+
The shell is both the conversation's operation binding (``request_close`` /
|
|
125
|
+
``drained``) and the kernel's pass observer; both interfaces are small and
|
|
126
|
+
keep the cancel story in one place.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __init__(
|
|
130
|
+
self,
|
|
131
|
+
*,
|
|
132
|
+
binding: AgentBinding,
|
|
133
|
+
node_id: str,
|
|
134
|
+
invocation_id: str,
|
|
135
|
+
resources: AgentNodeResources,
|
|
136
|
+
archive: AgentNodeArchive,
|
|
137
|
+
) -> None:
|
|
138
|
+
self._binding = binding
|
|
139
|
+
self._node_id = node_id
|
|
140
|
+
self._invocation_id = invocation_id
|
|
141
|
+
self._resources = resources
|
|
142
|
+
self._archive = archive
|
|
143
|
+
self._archive_attempt = 1
|
|
144
|
+
self._checkpoint: CoalescedCheckpoint | None = None
|
|
145
|
+
self._stats = SubAgentLogStats()
|
|
146
|
+
self._intermediate_buffer = IntermediateTextBuffer()
|
|
147
|
+
self._acp_translators: list[AcpUpdateTranslator] = []
|
|
148
|
+
self._acp_counters = AcpInvocationCounters()
|
|
149
|
+
self._display_name = binding.agent.display_name or binding.agent.name
|
|
150
|
+
self.origin = InvocationOrigin("workflow_node", resources.session_id, invocation_id, None, attempt=1)
|
|
151
|
+
"""The origin of the current scheduler attempt; every pass and fact of that attempt carries it."""
|
|
152
|
+
self._emitter = BoundEmitter(resources.bus, self.origin)
|
|
153
|
+
self._prepared = PreparedAgent()
|
|
154
|
+
self._unbind: Unbind | None = None
|
|
155
|
+
self._parts: KernelNodeParts | AcpNodeParts | None = None
|
|
156
|
+
self._is_prepared = False
|
|
157
|
+
self._abort_cause: AbortCause | None = None
|
|
158
|
+
self._run_task: asyncio.Task[InvocationOutcome] | None = None
|
|
159
|
+
self._close_task: asyncio.Task[None] | None = None
|
|
160
|
+
self._ticket: ContinuationTicket | None = None
|
|
161
|
+
self._resume = False
|
|
162
|
+
"""Whether the last pass left kernel history for the next attempt to continue."""
|
|
163
|
+
self._evidence = InvocationEvidence(invocation_id)
|
|
164
|
+
self._passes = 0
|
|
165
|
+
self._usage_total = 0
|
|
166
|
+
self._seed_item_id = new_analytics_id()
|
|
167
|
+
self._prompt = ""
|
|
168
|
+
self._active_run_input: list[Any] = []
|
|
169
|
+
self._pass_start_index = 0
|
|
170
|
+
|
|
171
|
+
# ------------------------------------------------------------------ identity
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def is_prepared(self) -> bool:
|
|
175
|
+
"""Whether this activation opened, even if its backend retired before retry."""
|
|
176
|
+
return self._is_prepared
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def _backend(self) -> KernelConversation | AcpConversation | None:
|
|
180
|
+
return self._parts.backend if self._parts is not None else None
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def invocation_id(self) -> str:
|
|
184
|
+
return self._invocation_id
|
|
185
|
+
|
|
186
|
+
def abort_cause(self) -> AbortCause | None:
|
|
187
|
+
"""The latched caller cause; also the kernel observer's abort-cause port."""
|
|
188
|
+
return self._abort_cause
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def evidence(self) -> InvocationEvidence:
|
|
192
|
+
"""Every converged pass of this activation, accumulated."""
|
|
193
|
+
return self._evidence
|
|
194
|
+
|
|
195
|
+
# ------------------------------------------------------------------ lifecycle
|
|
196
|
+
|
|
197
|
+
async def open(self, prompt: str, *, attempt: int = 1) -> None:
|
|
198
|
+
"""Build the conversation, bind this shell as its operation, and announce the invocation."""
|
|
199
|
+
self._bind_attempt(attempt)
|
|
200
|
+
await self._open_backend()
|
|
201
|
+
self._is_prepared = True
|
|
202
|
+
await self._emitter.publish(
|
|
203
|
+
InvocationStarted(
|
|
204
|
+
origin=self.origin,
|
|
205
|
+
agent_name=self._display_name,
|
|
206
|
+
tool_name=self._node_id,
|
|
207
|
+
session_id=self._session_id,
|
|
208
|
+
opening_prompt=self._user_prompt(prompt),
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def _bind_attempt(self, attempt: int) -> None:
|
|
213
|
+
"""Publish everything from here on as *attempt*; the previous attempt's pass has drained."""
|
|
214
|
+
if attempt != self.origin.attempt:
|
|
215
|
+
self.origin = replace(self.origin, attempt=attempt)
|
|
216
|
+
self._emitter = BoundEmitter(self._resources.bus, self.origin)
|
|
217
|
+
|
|
218
|
+
async def _open_backend(self) -> None:
|
|
219
|
+
conversation = await self._prepared.open(self._open_conversation)
|
|
220
|
+
self._unbind = conversation.bind_operation(self)
|
|
221
|
+
|
|
222
|
+
async def _reopen_backend(self) -> FailureReport | None:
|
|
223
|
+
"""Open a backend for a retry after the last one was retired; a failure fails only this attempt."""
|
|
224
|
+
try:
|
|
225
|
+
await self._open_backend()
|
|
226
|
+
except WorkflowStorageFailed:
|
|
227
|
+
raise
|
|
228
|
+
except Exception as exc:
|
|
229
|
+
logger.warning("workflow node %s: agent could not reopen", self._node_id, exc_info=True)
|
|
230
|
+
# A partial open may have left parts over a rolled-back conversation; the next attempt reopens.
|
|
231
|
+
await self._retire_backend()
|
|
232
|
+
return FailureReport(ErrorClass.AGENT_NON_TRANSIENT, f"{type(exc).__name__}: {exc}")
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
async def _retire_backend(self) -> None:
|
|
236
|
+
"""End a backend lifetime without ending the activation or its accounting.
|
|
237
|
+
|
|
238
|
+
A teardown failure is only logged: the attempt's own result stands, and the next attempt opens anew.
|
|
239
|
+
"""
|
|
240
|
+
unbind, self._unbind = self._unbind, None
|
|
241
|
+
if unbind is not None:
|
|
242
|
+
unbind()
|
|
243
|
+
try:
|
|
244
|
+
await self._prepared.aclose()
|
|
245
|
+
except Exception:
|
|
246
|
+
logger.warning("workflow node %s: retired agent did not close cleanly", self._node_id, exc_info=True)
|
|
247
|
+
finally:
|
|
248
|
+
self._prepared = PreparedAgent()
|
|
249
|
+
self._parts = None
|
|
250
|
+
self._ticket = None
|
|
251
|
+
self._resume = False
|
|
252
|
+
|
|
253
|
+
async def close(self) -> None:
|
|
254
|
+
"""Release the conversation, then drain the session's usage tail (including other publishers).
|
|
255
|
+
|
|
256
|
+
Safe to call more than once. The shared drain keeps session persistence behind usage delivery.
|
|
257
|
+
"""
|
|
258
|
+
if self._close_task is None:
|
|
259
|
+
self._close_task = asyncio.create_task(self._close(), name="chrys.workflow.agent.close")
|
|
260
|
+
await finish_close(self._close_task)
|
|
261
|
+
|
|
262
|
+
async def _close(self) -> None:
|
|
263
|
+
_PASS_SHELL.set(self)
|
|
264
|
+
unbind, self._unbind = self._unbind, None
|
|
265
|
+
if unbind is not None:
|
|
266
|
+
unbind()
|
|
267
|
+
await self._flush_progress()
|
|
268
|
+
try:
|
|
269
|
+
await self._prepared.aclose()
|
|
270
|
+
if self._checkpoint is not None:
|
|
271
|
+
await self._checkpoint.close()
|
|
272
|
+
finally:
|
|
273
|
+
await self._resources.usage_publisher.drain()
|
|
274
|
+
|
|
275
|
+
async def _flush_progress(self) -> None:
|
|
276
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
277
|
+
try:
|
|
278
|
+
await self._parts.events.flush_progress()
|
|
279
|
+
except Exception:
|
|
280
|
+
logger.debug("workflow node %s: progress flush failed", self._node_id, exc_info=True)
|
|
281
|
+
|
|
282
|
+
async def run(
|
|
283
|
+
self,
|
|
284
|
+
prompt: str,
|
|
285
|
+
*,
|
|
286
|
+
timeout: float | None,
|
|
287
|
+
trajectory_context: TrajectoryContext | None,
|
|
288
|
+
attempt: int = 1,
|
|
289
|
+
) -> AgentAttemptResult:
|
|
290
|
+
"""Archive this attempt after its pass has drained, including cancellation."""
|
|
291
|
+
self._bind_attempt(attempt)
|
|
292
|
+
self._checkpoint = CoalescedCheckpoint(self._save_transcript)
|
|
293
|
+
self._archive_attempt = attempt
|
|
294
|
+
self._acp_translators.clear()
|
|
295
|
+
result: AgentAttemptResult | None = None
|
|
296
|
+
error = ""
|
|
297
|
+
try:
|
|
298
|
+
if self._backend is None and (failure := await self._reopen_backend()) is not None:
|
|
299
|
+
result = AgentAttemptResult("failed", failure=failure)
|
|
300
|
+
return result
|
|
301
|
+
result = await self._run(prompt, timeout=timeout, trajectory_context=trajectory_context)
|
|
302
|
+
return result
|
|
303
|
+
except asyncio.CancelledError:
|
|
304
|
+
raise
|
|
305
|
+
except Exception as exc:
|
|
306
|
+
error = f"{type(exc).__name__}: {exc}"
|
|
307
|
+
raise
|
|
308
|
+
finally:
|
|
309
|
+
await finish_close(asyncio.create_task(self._finish_attempt(result, error)))
|
|
310
|
+
|
|
311
|
+
async def _finish_attempt(self, result: AgentAttemptResult | None, error: str) -> None:
|
|
312
|
+
# Delivery belongs to the pass boundary, even while the activation is
|
|
313
|
+
# retained for outgoing-condition evaluation and possible retries.
|
|
314
|
+
_PASS_SHELL.set(self)
|
|
315
|
+
await self._flush_progress()
|
|
316
|
+
await self._resources.usage_publisher.drain()
|
|
317
|
+
await self._require_checkpoint().close()
|
|
318
|
+
await self._save_transcript(
|
|
319
|
+
status=result.kind if result is not None else "failed" if error else "cancelled",
|
|
320
|
+
error=result.failure.message if result is not None and result.failure is not None else error,
|
|
321
|
+
)
|
|
322
|
+
if (
|
|
323
|
+
isinstance(self._backend, AcpConversation)
|
|
324
|
+
and result is not None
|
|
325
|
+
and result.failure is not None
|
|
326
|
+
and result.failure.error_class is ErrorClass.AGENT_TIMEOUT
|
|
327
|
+
):
|
|
328
|
+
await self._retire_backend()
|
|
329
|
+
|
|
330
|
+
async def _run(
|
|
331
|
+
self, prompt: str, *, timeout: float | None, trajectory_context: TrajectoryContext | None
|
|
332
|
+
) -> AgentAttemptResult:
|
|
333
|
+
"""Execute one pass for *prompt*; a retry pass resumes what the failed pass left when it can."""
|
|
334
|
+
backend = self._backend
|
|
335
|
+
if backend is None:
|
|
336
|
+
raise RuntimeError("WorkflowAgentShell.run before open")
|
|
337
|
+
if self._run_task is not None and not self._run_task.done():
|
|
338
|
+
raise RuntimeError("an agent pass is already running for this activation")
|
|
339
|
+
if self._abort_cause is not None:
|
|
340
|
+
return AgentAttemptResult("cancelled")
|
|
341
|
+
self._prompt = prompt
|
|
342
|
+
if trajectory_context is not None:
|
|
343
|
+
trajectory_context = trajectory_context.with_actor(
|
|
344
|
+
workflow_node_actor(self._resources.session_id, self._invocation_id)
|
|
345
|
+
)
|
|
346
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
347
|
+
self._parts.trace.context = trajectory_context
|
|
348
|
+
if isinstance(backend, AcpConversation):
|
|
349
|
+
backend.bind_trajectory(
|
|
350
|
+
trajectory_context,
|
|
351
|
+
boundary_operation_id=trajectory_context.innermost_model_operation_id
|
|
352
|
+
if trajectory_context is not None
|
|
353
|
+
else None,
|
|
354
|
+
)
|
|
355
|
+
if trajectory_context is not None and isinstance(self._parts, KernelNodeParts):
|
|
356
|
+
self._parts.run_kwargs["client_kwargs"] = {
|
|
357
|
+
**self._parts.run_kwargs.get("client_kwargs", {}),
|
|
358
|
+
TRAJECTORY_CONTEXT_KWARG: trajectory_context,
|
|
359
|
+
}
|
|
360
|
+
request = self._next_request(backend)
|
|
361
|
+
self._passes += 1
|
|
362
|
+
run_task = asyncio.create_task(self._pass(backend, request))
|
|
363
|
+
self._run_task = run_task
|
|
364
|
+
timed_out = False
|
|
365
|
+
try:
|
|
366
|
+
if timeout is None:
|
|
367
|
+
outcome = await run_task
|
|
368
|
+
else:
|
|
369
|
+
done, _pending = await asyncio.wait({run_task}, timeout=timeout)
|
|
370
|
+
if run_task not in done:
|
|
371
|
+
timed_out = True
|
|
372
|
+
await self.abort(AbortCause.CALLER_TIMEOUT)
|
|
373
|
+
done, _pending = await asyncio.wait({run_task}, timeout=ABORT_GRACE)
|
|
374
|
+
if run_task not in done:
|
|
375
|
+
run_task.cancel()
|
|
376
|
+
outcome = await run_task
|
|
377
|
+
except asyncio.CancelledError:
|
|
378
|
+
# The runner's attempt task was cancelled around us: converge the pass before leaving.
|
|
379
|
+
if self._abort_cause is None:
|
|
380
|
+
self._abort_cause = AbortCause.RUN_TERMINAL
|
|
381
|
+
backend.latch_abort(self._abort_cause)
|
|
382
|
+
run_task.cancel()
|
|
383
|
+
await asyncio.gather(run_task, return_exceptions=True)
|
|
384
|
+
raise
|
|
385
|
+
except (StaleContinuation, UnsupportedRequest, OverlappingRun, PreparedClosed) as exc:
|
|
386
|
+
self._ticket = None
|
|
387
|
+
return AgentAttemptResult(
|
|
388
|
+
"failed", failure=FailureReport(ErrorClass.AGENT_NON_TRANSIENT, f"{type(exc).__name__}: {exc}")
|
|
389
|
+
)
|
|
390
|
+
finally:
|
|
391
|
+
if timed_out and self._abort_cause is AbortCause.CALLER_TIMEOUT:
|
|
392
|
+
self._abort_cause = None # a timeout ends the pass, not the activation
|
|
393
|
+
return await self._project(outcome, timeout=timeout)
|
|
394
|
+
|
|
395
|
+
async def _pass(self, backend: KernelConversation | AcpConversation, request: RunRequest) -> InvocationOutcome:
|
|
396
|
+
"""Run the pass marked as this shell's: the kernel's tasks for it inherit the mark with the context."""
|
|
397
|
+
_PASS_SHELL.set(self)
|
|
398
|
+
return await backend.run(request)
|
|
399
|
+
|
|
400
|
+
def holds(self, task: asyncio.Task[Any] | None) -> bool:
|
|
401
|
+
"""True when *task* is the live pass or one started under it: the run waits for all of them.
|
|
402
|
+
|
|
403
|
+
The kernel runs the pass's attempt and each of its tool calls on tasks of its own, and the usage
|
|
404
|
+
callback schedules the progress publishes on others; an event published from any of them reaches
|
|
405
|
+
its subscribers on that task.
|
|
406
|
+
"""
|
|
407
|
+
if task is None:
|
|
408
|
+
return False
|
|
409
|
+
return task is self._run_task or task.get_context().get(_PASS_SHELL) is self
|
|
410
|
+
|
|
411
|
+
def set_approval_mode(self, mode: ApprovalMode) -> None:
|
|
412
|
+
"""Apply the engine's launch policy to the live pass's subsequent tool calls, sub-agents included."""
|
|
413
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
414
|
+
self._parts.approval.set_approval_mode(mode)
|
|
415
|
+
if self._parts.sub_agent_tools is not None:
|
|
416
|
+
self._parts.sub_agent_tools.set_approval_mode(mode)
|
|
417
|
+
|
|
418
|
+
def _latch(self, cause: AbortCause) -> None:
|
|
419
|
+
if self._abort_cause is None or self._abort_cause not in _TERMINAL_CAUSES:
|
|
420
|
+
self._abort_cause = cause
|
|
421
|
+
|
|
422
|
+
async def abort(self, cause: AbortCause) -> None:
|
|
423
|
+
"""Latch *cause* and converge the in-flight pass, if any, tearing its live sub-agents down first."""
|
|
424
|
+
self._latch(cause)
|
|
425
|
+
backend = self._backend
|
|
426
|
+
if backend is None:
|
|
427
|
+
return
|
|
428
|
+
if isinstance(self._parts, KernelNodeParts) and self._parts.sub_agent_tools is not None:
|
|
429
|
+
# Running children cancel their attempt, so long inner tool calls stop before the pass
|
|
430
|
+
# task itself is cancelled.
|
|
431
|
+
await self._parts.sub_agent_tools.cascade_abort_all()
|
|
432
|
+
backend.latch_abort(cause)
|
|
433
|
+
handle = backend.active_handle
|
|
434
|
+
if handle is not None:
|
|
435
|
+
await backend.abort(handle, cause)
|
|
436
|
+
|
|
437
|
+
# ------------------------------------------------------------------ OperationBinding
|
|
438
|
+
|
|
439
|
+
def request_close(self, cause: AbortCause) -> None:
|
|
440
|
+
self._latch(cause)
|
|
441
|
+
if self._backend is not None:
|
|
442
|
+
self._backend.latch_abort(cause)
|
|
443
|
+
if self._run_task is not None and not self._run_task.done():
|
|
444
|
+
self._run_task.cancel()
|
|
445
|
+
|
|
446
|
+
@property
|
|
447
|
+
def drained(self) -> Awaitable[None]:
|
|
448
|
+
return self._drain()
|
|
449
|
+
|
|
450
|
+
async def _drain(self) -> None:
|
|
451
|
+
task = self._run_task
|
|
452
|
+
if task is not None and not task.done():
|
|
453
|
+
await asyncio.gather(task, return_exceptions=True)
|
|
454
|
+
|
|
455
|
+
# ------------------------------------------------------------------ KernelPassObserver
|
|
456
|
+
|
|
457
|
+
async def begin(self, request: RunRequest, resources: PassResources) -> None:
|
|
458
|
+
parts = self._require_kernel_parts()
|
|
459
|
+
if request.intent is not RunIntent.FRESH and (not request.messages or self._has_live_continuation_token()):
|
|
460
|
+
# An admitted pass that continues retained work, or polls the response an earlier pass left
|
|
461
|
+
# running, carries the previous attempt's transcript on; the first fact of the attempt, so a
|
|
462
|
+
# presentation starts from that transcript.
|
|
463
|
+
await self._emitter.publish(
|
|
464
|
+
InvocationResumed(origin=request.origin, agent_name=self._display_name, session_id=self._session_id)
|
|
465
|
+
)
|
|
466
|
+
# Bound before the start hooks, which open the pass's hosted presentation under this origin.
|
|
467
|
+
parts.approval.bind_publisher(self._emitter)
|
|
468
|
+
parts.events.bind_origin(request.origin)
|
|
469
|
+
self._intermediate_buffer.drain()
|
|
470
|
+
self._pass_start_index = len(parts.history.messages())
|
|
471
|
+
resources.begin()
|
|
472
|
+
self._active_run_input = list(request.messages)
|
|
473
|
+
await self._save_transcript()
|
|
474
|
+
|
|
475
|
+
async def succeeded(self, response: AgentResponse[Any], /) -> None:
|
|
476
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
477
|
+
await self._parts.events.reconcile_hosted_response(response.messages)
|
|
478
|
+
|
|
479
|
+
async def failed(self, error: Exception, /) -> None:
|
|
480
|
+
parts = self._require_kernel_parts()
|
|
481
|
+
parts.history.repair_after_failure(self._active_run_input, self._pass_start_index)
|
|
482
|
+
if self._abort_cause is None:
|
|
483
|
+
# An aborted pass can still end in an error; finished() settles its cards as interrupted.
|
|
484
|
+
await parts.events.reject_hosted_attempt(clean_error_message(error), status=HostedToolStatus.FAILED)
|
|
485
|
+
|
|
486
|
+
async def finished(self) -> None:
|
|
487
|
+
# A failed or interrupted pass publishes no outcome; its buffered text
|
|
488
|
+
# belongs to this pass's transcript, not the next one.
|
|
489
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
490
|
+
await self._parts.events.finish_intermediate_text()
|
|
491
|
+
if self._abort_cause is not None:
|
|
492
|
+
# An aborted pass settles no hosted card; a resumed attempt would carry it on still running.
|
|
493
|
+
await self._parts.events.reject_hosted_attempt("Execution interrupted")
|
|
494
|
+
|
|
495
|
+
async def interrupt(self) -> None:
|
|
496
|
+
pass
|
|
497
|
+
|
|
498
|
+
def cancelled(self) -> None:
|
|
499
|
+
pass
|
|
500
|
+
|
|
501
|
+
# ------------------------------------------------------------------ construction
|
|
502
|
+
|
|
503
|
+
async def _open_conversation(self, conversation: Conversation) -> Conversation:
|
|
504
|
+
callbacks = AgentNodeCallbacks(
|
|
505
|
+
observer=self,
|
|
506
|
+
publish_intermediate=self._publish_intermediate,
|
|
507
|
+
checkpoint=self._mark_dirty,
|
|
508
|
+
usage=self._on_usage,
|
|
509
|
+
side_call_usage=self._on_side_call_usage,
|
|
510
|
+
validation_retry=self._publish_validation_retry,
|
|
511
|
+
wire_retry=self._publish_wire_retry,
|
|
512
|
+
service_retry=self._publish_service_retry,
|
|
513
|
+
interruptible_sleep=self._interruptible_sleep,
|
|
514
|
+
emitter=lambda: self._emitter,
|
|
515
|
+
acp_usage=self._on_acp_usage,
|
|
516
|
+
adopt_translator=self._adopt_acp_translator,
|
|
517
|
+
acp_counters=self._acp_counters,
|
|
518
|
+
)
|
|
519
|
+
if self._binding.agent.acp is not None:
|
|
520
|
+
self._parts = build_acp_node(
|
|
521
|
+
conversation,
|
|
522
|
+
binding=self._binding,
|
|
523
|
+
node_id=self._node_id,
|
|
524
|
+
invocation_id=self._invocation_id,
|
|
525
|
+
res=self._resources,
|
|
526
|
+
archive=self._archive,
|
|
527
|
+
callbacks=callbacks,
|
|
528
|
+
)
|
|
529
|
+
else:
|
|
530
|
+
self._parts = await build_kernel_node(
|
|
531
|
+
conversation,
|
|
532
|
+
binding=self._binding,
|
|
533
|
+
node_id=self._node_id,
|
|
534
|
+
invocation_id=self._invocation_id,
|
|
535
|
+
res=self._resources,
|
|
536
|
+
archive=self._archive,
|
|
537
|
+
callbacks=callbacks,
|
|
538
|
+
intermediate_buffer=self._intermediate_buffer,
|
|
539
|
+
stats=self._stats,
|
|
540
|
+
)
|
|
541
|
+
# Construction awaits sub-agent registration, MCP connection and skill discovery; a mode
|
|
542
|
+
# change that arrived meanwhile found no parts to apply to, so the launch policy is re-read.
|
|
543
|
+
self.set_approval_mode(self._resources.approval_mode())
|
|
544
|
+
return conversation
|
|
545
|
+
|
|
546
|
+
def _on_acp_usage(
|
|
547
|
+
self,
|
|
548
|
+
total: int,
|
|
549
|
+
input_tokens: int,
|
|
550
|
+
output_tokens: int,
|
|
551
|
+
local_tokens: int,
|
|
552
|
+
calibration_ratio: float,
|
|
553
|
+
system_overhead_tokens: int,
|
|
554
|
+
cache_hit_tokens: int | None,
|
|
555
|
+
max_context_tokens: int | None,
|
|
556
|
+
agent_profile: str,
|
|
557
|
+
usage_source_id: str,
|
|
558
|
+
total_usage_tokens: int,
|
|
559
|
+
) -> None:
|
|
560
|
+
# ACP reports each transport once; the archive and graph summarize the whole activation.
|
|
561
|
+
self._usage_total += total_usage_tokens
|
|
562
|
+
self._stats.record_usage(total, self._usage_total)
|
|
563
|
+
self._resources.usage_publisher.accumulate_invocation_usage(
|
|
564
|
+
total,
|
|
565
|
+
input_tokens=input_tokens,
|
|
566
|
+
output_tokens=output_tokens,
|
|
567
|
+
local_tokens=local_tokens,
|
|
568
|
+
calibration_ratio=calibration_ratio,
|
|
569
|
+
system_overhead_tokens=system_overhead_tokens,
|
|
570
|
+
cache_hit_tokens=cache_hit_tokens,
|
|
571
|
+
max_context_tokens=max_context_tokens,
|
|
572
|
+
agent_profile=agent_profile,
|
|
573
|
+
usage_source_id=usage_source_id,
|
|
574
|
+
authoritative_total=total_usage_tokens,
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
# ------------------------------------------------------------------ passes
|
|
578
|
+
|
|
579
|
+
def _next_request(self, backend: KernelConversation | AcpConversation) -> RunRequest:
|
|
580
|
+
"""Resume what the last pass left: its live ticket, its repaired history, or nothing after a success."""
|
|
581
|
+
ticket, self._ticket = self._ticket, None
|
|
582
|
+
if isinstance(backend, AcpConversation):
|
|
583
|
+
# Every ACP pass runs a new session from the prompt; a ticket only names the failed one.
|
|
584
|
+
return RunRequest(
|
|
585
|
+
self._seed_input(), RunIntent.RETRY if ticket is not None else RunIntent.FRESH, self.origin, ticket
|
|
586
|
+
)
|
|
587
|
+
history = self._require_kernel_parts().history
|
|
588
|
+
if ticket is not None and backend.continuation_is_live(ticket, self.origin):
|
|
589
|
+
return RunRequest(history.retry_input(self._seed_input), RunIntent.RETRY, self.origin, ticket)
|
|
590
|
+
if self._resume:
|
|
591
|
+
return RunRequest(history.retry_input(self._seed_input), RunIntent.CONTINUE, self.origin, None)
|
|
592
|
+
# A completed body is run again from the prompt when a later phase of its attempt failed.
|
|
593
|
+
self._drop_continuation_token()
|
|
594
|
+
if self._passes:
|
|
595
|
+
backend.history_state = {} # a fresh pass starts from the prompt, not from a stale transcript
|
|
596
|
+
return RunRequest(self._seed_input(), RunIntent.FRESH, self.origin, None)
|
|
597
|
+
|
|
598
|
+
async def _project(self, outcome: InvocationOutcome, *, timeout: float | None) -> AgentAttemptResult:
|
|
599
|
+
self._evidence = self._evidence.add(outcome.effects)
|
|
600
|
+
self._resume = False
|
|
601
|
+
if isinstance(outcome, Ok):
|
|
602
|
+
self._ticket = None
|
|
603
|
+
if isinstance(outcome.backend_payload, AgentResponse):
|
|
604
|
+
# The node's value is the final segment, as a sub-agent's result is; what the agent wrote
|
|
605
|
+
# between tool calls is already in the transcript.
|
|
606
|
+
segment = FinalSegment.of(outcome.backend_payload)
|
|
607
|
+
value, transcript = segment.result, segment.transcript
|
|
608
|
+
else:
|
|
609
|
+
# An ACP result is left alone, since the profile's result mode already chose its extent.
|
|
610
|
+
value = transcript = _response_text(outcome)
|
|
611
|
+
if isinstance(self._backend, AcpConversation) and self._backend.transcript_final_text is not None:
|
|
612
|
+
transcript = self._backend.transcript_final_text
|
|
613
|
+
await self._emitter.publish(
|
|
614
|
+
InvocationMessage(
|
|
615
|
+
origin=self.origin,
|
|
616
|
+
agent_name=self._display_name,
|
|
617
|
+
text=transcript,
|
|
618
|
+
is_final=True,
|
|
619
|
+
session_id=self._session_id,
|
|
620
|
+
)
|
|
621
|
+
)
|
|
622
|
+
return AgentAttemptResult("completed", text=value)
|
|
623
|
+
if isinstance(outcome, Failed):
|
|
624
|
+
self._ticket = outcome.continuation
|
|
625
|
+
self._resume = isinstance(self._parts, KernelNodeParts)
|
|
626
|
+
transient = self._retryable(outcome)
|
|
627
|
+
approved = transient and not self._repeats_hosted_work(outcome, outcome.exception)
|
|
628
|
+
error_class = ErrorClass.AGENT_TRANSIENT if transient else ErrorClass.AGENT_NON_TRANSIENT
|
|
629
|
+
return AgentAttemptResult(
|
|
630
|
+
"failed", failure=FailureReport(error_class, outcome.error, backend_approved=approved)
|
|
631
|
+
)
|
|
632
|
+
if not isinstance(outcome, Aborted):
|
|
633
|
+
raise TypeError("Expected an aborted agent outcome after handling success and failure.")
|
|
634
|
+
self._ticket = None
|
|
635
|
+
# An aborted request is abandoned, never polled again: its retry creates a new one. A response
|
|
636
|
+
# still running at the provider may yet run hosted tools that the new request would repeat.
|
|
637
|
+
abandoned_response = self._has_live_continuation_token()
|
|
638
|
+
self._drop_continuation_token()
|
|
639
|
+
if outcome.cause is AbortCause.CALLER_TIMEOUT:
|
|
640
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
641
|
+
# The deadline cut the pass off before its history was saved: keep the completed tool
|
|
642
|
+
# work, so the next attempt continues after it instead of running it again.
|
|
643
|
+
self._parts.history.repair_after_failure(self._active_run_input, self._pass_start_index)
|
|
644
|
+
self._resume = True
|
|
645
|
+
limit = f"{timeout:g}s" if timeout is not None else "its deadline"
|
|
646
|
+
return AgentAttemptResult(
|
|
647
|
+
"failed",
|
|
648
|
+
failure=FailureReport(
|
|
649
|
+
ErrorClass.AGENT_TIMEOUT,
|
|
650
|
+
f"no response within {limit}",
|
|
651
|
+
backend_approved=not abandoned_response and not self._repeats_hosted_work(outcome, None),
|
|
652
|
+
),
|
|
653
|
+
)
|
|
654
|
+
return AgentAttemptResult("cancelled")
|
|
655
|
+
|
|
656
|
+
def _retryable(self, outcome: Failed) -> bool:
|
|
657
|
+
"""Whether repeating the failed pass can succeed: a clear refusal, quota or configuration error cannot."""
|
|
658
|
+
if outcome.category is not FailureCategory.UNCLASSIFIED:
|
|
659
|
+
return outcome.category in _RETRYABLE_ACP_CATEGORIES
|
|
660
|
+
exception = outcome.exception
|
|
661
|
+
if exception is None:
|
|
662
|
+
return False
|
|
663
|
+
# A stall already outlasted the in-pass retries; a later attempt may find the stream moving again.
|
|
664
|
+
return is_retryable(exception) or classify_error(exception).kind is ErrorKind.STREAM_STALLED
|
|
665
|
+
|
|
666
|
+
def _repeats_hosted_work(self, outcome: Failed | Aborted, exception: Exception | None) -> bool:
|
|
667
|
+
"""Whether resuming would run provider-hosted tool calls a second time.
|
|
668
|
+
|
|
669
|
+
Resumed history keeps every completed exchange, so only the last request's hosted work is at risk
|
|
670
|
+
— named by its validation error, or by the middleware's probe unless the repaired history kept the
|
|
671
|
+
response that ran it. Under service-side storage the history may hold none of the pass, so any hosted
|
|
672
|
+
work of the pass counts. A live continuation token makes the retry a poll of the response already
|
|
673
|
+
created.
|
|
674
|
+
"""
|
|
675
|
+
parts = self._parts
|
|
676
|
+
if not isinstance(parts, KernelNodeParts) or self._has_live_continuation_token():
|
|
677
|
+
return False
|
|
678
|
+
if exception is not None and hosted_commits_from_error(exception):
|
|
679
|
+
return True
|
|
680
|
+
if parts.backend.service_session_storage_enabled:
|
|
681
|
+
return outcome.effects.hosted_observed.observed > 0
|
|
682
|
+
return bool(parts.hosted_unkept(parts.history.messages()[self._pass_start_index :]))
|
|
683
|
+
|
|
684
|
+
def _has_live_continuation_token(self) -> bool:
|
|
685
|
+
return isinstance(self._parts, KernelNodeParts) and has_live_continuation_token(self._parts.run_kwargs)
|
|
686
|
+
|
|
687
|
+
def _drop_continuation_token(self) -> None:
|
|
688
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
689
|
+
drop_continuation_token(self._parts.run_kwargs)
|
|
690
|
+
|
|
691
|
+
async def _interruptible_sleep(self, seconds: int) -> bool:
|
|
692
|
+
for _ in range(max(0, seconds)):
|
|
693
|
+
if self._abort_cause is not None:
|
|
694
|
+
return True
|
|
695
|
+
await asyncio.sleep(1)
|
|
696
|
+
return self._abort_cause is not None
|
|
697
|
+
|
|
698
|
+
# ------------------------------------------------------------------ history
|
|
699
|
+
|
|
700
|
+
def _require_checkpoint(self) -> CoalescedCheckpoint:
|
|
701
|
+
if self._checkpoint is None:
|
|
702
|
+
raise RuntimeError("The agent node checkpoint has not been opened.")
|
|
703
|
+
return self._checkpoint
|
|
704
|
+
|
|
705
|
+
def _require_kernel_parts(self) -> KernelNodeParts:
|
|
706
|
+
if not isinstance(self._parts, KernelNodeParts):
|
|
707
|
+
raise TypeError("A kernel agent pass requires kernel node resources.")
|
|
708
|
+
return self._parts
|
|
709
|
+
|
|
710
|
+
async def _mark_dirty(self) -> None:
|
|
711
|
+
self._require_checkpoint().changed()
|
|
712
|
+
|
|
713
|
+
async def _adopt_acp_translator(self, translator: AcpUpdateTranslator) -> None:
|
|
714
|
+
self._acp_translators.append(translator)
|
|
715
|
+
if self._checkpoint is not None:
|
|
716
|
+
translator.on_audit_changed = self._checkpoint.changed
|
|
717
|
+
await self._save_transcript()
|
|
718
|
+
|
|
719
|
+
async def _save_transcript(self, *, status: str = "running", error: str = "") -> None:
|
|
720
|
+
state = None
|
|
721
|
+
acp_state = None
|
|
722
|
+
if isinstance(self._backend, AcpConversation):
|
|
723
|
+
acp_state = {
|
|
724
|
+
"prompt": self._user_prompt(self._prompt),
|
|
725
|
+
"translated_updates": [
|
|
726
|
+
{**item, "attempt": translator.attempt}
|
|
727
|
+
for translator in self._acp_translators
|
|
728
|
+
for item in translator.translated_updates
|
|
729
|
+
],
|
|
730
|
+
"successful_attempt": self._backend.transport_ordinal if status == "completed" else None,
|
|
731
|
+
}
|
|
732
|
+
self._stats.tool_call_count = max(
|
|
733
|
+
(self._backend.completed_tool_calls, *(t.completed_count for t in self._acp_translators))
|
|
734
|
+
)
|
|
735
|
+
self._stats.usage_unreported_attempts = self._backend.usage_unreported_attempts
|
|
736
|
+
elif isinstance(self._parts, KernelNodeParts):
|
|
737
|
+
# Keep message identities while merging into a detached list. This
|
|
738
|
+
# reuses the same recovery merge as Chat without mutating the
|
|
739
|
+
# active model history or deduplicating repeated provider call IDs.
|
|
740
|
+
state = dict(self._parts.history.state())
|
|
741
|
+
state["messages"] = list(state.get("messages", []))
|
|
742
|
+
input_message = active_input_message(self._active_run_input)
|
|
743
|
+
if not state["messages"] and input_message is not None:
|
|
744
|
+
state["messages"].append(input_message)
|
|
745
|
+
manager = SessionHistoryManager()
|
|
746
|
+
manager.bind(state)
|
|
747
|
+
manager.merge_loop_messages(self._parts.history.recorder, insert_index=self._pass_start_index)
|
|
748
|
+
stamp_history_item_ids(state)
|
|
749
|
+
await self._archive.write(
|
|
750
|
+
attempt=self._archive_attempt,
|
|
751
|
+
status=status,
|
|
752
|
+
error=error,
|
|
753
|
+
state=state,
|
|
754
|
+
acp_state=acp_state,
|
|
755
|
+
stats=self._stats,
|
|
756
|
+
)
|
|
757
|
+
if status != "running" and isinstance(self._parts, KernelNodeParts) and self._parts.sub_agent_tools is not None:
|
|
758
|
+
# Children's control records go once the attempt's terminal transcript is on disk, as after
|
|
759
|
+
# a chat turn's save; a running checkpoint is best-effort and may predate a child's result.
|
|
760
|
+
self._parts.sub_agent_tools.finalize_pending_cleanups()
|
|
761
|
+
|
|
762
|
+
def _user_prompt(self, prompt: str) -> str:
|
|
763
|
+
"""The same user text feeds the conversation and its live presentation."""
|
|
764
|
+
if self._binding.agent.acp is not None and self._binding.instructions_suffix:
|
|
765
|
+
return f"{prompt}\n\n{self._binding.instructions_suffix}"
|
|
766
|
+
return prompt
|
|
767
|
+
|
|
768
|
+
def _seed_input(self) -> list[Any]:
|
|
769
|
+
message = Message("user", [self._user_prompt(self._prompt)])
|
|
770
|
+
ensure_analytics_item_id(message.additional_properties, item_id=self._seed_item_id)
|
|
771
|
+
return [message]
|
|
772
|
+
|
|
773
|
+
# ------------------------------------------------------------------ events
|
|
774
|
+
|
|
775
|
+
@property
|
|
776
|
+
def _session_id(self) -> str | None:
|
|
777
|
+
return self._resources.session_id or None
|
|
778
|
+
|
|
779
|
+
async def _publish_intermediate(self, text: str) -> None:
|
|
780
|
+
self._intermediate_buffer.new_batch()
|
|
781
|
+
await self._emitter.publish(
|
|
782
|
+
InvocationMessage(
|
|
783
|
+
origin=self.origin,
|
|
784
|
+
agent_name=self._display_name,
|
|
785
|
+
text=text,
|
|
786
|
+
is_final=False,
|
|
787
|
+
is_intermediate=True,
|
|
788
|
+
session_id=self._session_id,
|
|
789
|
+
)
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
async def _publish_validation_retry(self, info: RetryAttemptInfo) -> None:
|
|
793
|
+
await self._emitter.publish(
|
|
794
|
+
InvocationRetryAttempt(
|
|
795
|
+
scope="wire",
|
|
796
|
+
origin=self.origin,
|
|
797
|
+
agent_name=self._display_name,
|
|
798
|
+
message=f"Invalid response: {info.reason}",
|
|
799
|
+
attempt=info.attempt,
|
|
800
|
+
max_attempts=info.max_attempts,
|
|
801
|
+
delay_seconds=int(info.delay_seconds),
|
|
802
|
+
session_id=self._session_id,
|
|
803
|
+
)
|
|
804
|
+
)
|
|
805
|
+
|
|
806
|
+
async def _publish_wire_retry(
|
|
807
|
+
self, message: str, attempt: int, max_attempts: int, delay_seconds: int, exc: BaseException
|
|
808
|
+
) -> None:
|
|
809
|
+
await self._publish_retry(message, attempt, max_attempts, delay_seconds, exc, scope="wire")
|
|
810
|
+
|
|
811
|
+
async def _publish_service_retry(
|
|
812
|
+
self, message: str, attempt: int, max_attempts: int, delay_seconds: int, exc: BaseException
|
|
813
|
+
) -> None:
|
|
814
|
+
await self._publish_retry(message, attempt, max_attempts, delay_seconds, exc, scope="run")
|
|
815
|
+
|
|
816
|
+
async def _publish_retry(
|
|
817
|
+
self,
|
|
818
|
+
message: str,
|
|
819
|
+
attempt: int,
|
|
820
|
+
max_attempts: int,
|
|
821
|
+
delay_seconds: int,
|
|
822
|
+
exc: BaseException,
|
|
823
|
+
*,
|
|
824
|
+
scope: Literal["wire", "run"],
|
|
825
|
+
) -> None:
|
|
826
|
+
emitter = self._emitter
|
|
827
|
+
if isinstance(self._parts, KernelNodeParts) and not self._has_live_continuation_token():
|
|
828
|
+
# The retried request's hosted cards will not finish; a poll of a created response still may.
|
|
829
|
+
await self._parts.events.reject_hosted_attempt(message)
|
|
830
|
+
display_message, display_hint = display_fields(exc, retry_notice=True)
|
|
831
|
+
await emitter.publish(
|
|
832
|
+
InvocationRetryAttempt(
|
|
833
|
+
scope=scope,
|
|
834
|
+
origin=emitter.origin,
|
|
835
|
+
agent_name=self._display_name,
|
|
836
|
+
message=message,
|
|
837
|
+
attempt=attempt,
|
|
838
|
+
max_attempts=max_attempts,
|
|
839
|
+
delay_seconds=delay_seconds,
|
|
840
|
+
session_id=self._session_id,
|
|
841
|
+
display_message=display_message,
|
|
842
|
+
display_hint=display_hint,
|
|
843
|
+
)
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
def _on_side_call_usage(self, usage_details: Mapping[str, Any]) -> None:
|
|
847
|
+
"""Charge summary generation to this node without replacing its context-window reading."""
|
|
848
|
+
self._resources.usage_publisher.accumulate_side_call_usage(
|
|
849
|
+
usage_details,
|
|
850
|
+
agent_profile=self._binding.agent.name,
|
|
851
|
+
usage_source_id=f"{self._invocation_id}:last_words",
|
|
852
|
+
max_context_tokens=self._binding.model.max_context_tokens if self._binding.model is not None else None,
|
|
853
|
+
)
|
|
854
|
+
self._usage_total += int(usage_details.get("total_token_count") or 0)
|
|
855
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
856
|
+
self._parts.events.record_usage(self._stats.total_tokens, self._usage_total)
|
|
857
|
+
|
|
858
|
+
# Positional args mirror UsageTrackingMiddleware._fire_callback. New fields must be named and
|
|
859
|
+
# forwarded here as well: *_rest tolerates extra arguments but does not account for their values.
|
|
860
|
+
def _on_usage(
|
|
861
|
+
self,
|
|
862
|
+
total: int,
|
|
863
|
+
input_tokens: int = 0,
|
|
864
|
+
output_tokens: int = 0,
|
|
865
|
+
local_tokens: int = 0,
|
|
866
|
+
calibration_ratio: float = 1.0,
|
|
867
|
+
system_overhead_tokens: int = 0,
|
|
868
|
+
cache_hit_tokens: int | None = None,
|
|
869
|
+
_calibration_initialized: bool = False,
|
|
870
|
+
use_local_context_estimate: bool = False,
|
|
871
|
+
*_rest: Any,
|
|
872
|
+
) -> None:
|
|
873
|
+
self._usage_total += total
|
|
874
|
+
if isinstance(self._parts, KernelNodeParts):
|
|
875
|
+
self._parts.events.record_usage(total, self._usage_total)
|
|
876
|
+
self._resources.usage_publisher.accumulate_invocation_usage(
|
|
877
|
+
total,
|
|
878
|
+
input_tokens=input_tokens,
|
|
879
|
+
output_tokens=output_tokens,
|
|
880
|
+
local_tokens=local_tokens,
|
|
881
|
+
calibration_ratio=calibration_ratio,
|
|
882
|
+
system_overhead_tokens=system_overhead_tokens,
|
|
883
|
+
cache_hit_tokens=cache_hit_tokens,
|
|
884
|
+
max_context_tokens=self._binding.model.max_context_tokens if self._binding.model is not None else None,
|
|
885
|
+
agent_profile=self._binding.agent.name,
|
|
886
|
+
usage_source_id=self._invocation_id,
|
|
887
|
+
use_local_context_estimate=use_local_context_estimate,
|
|
888
|
+
)
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
def _response_text(outcome: Ok) -> str:
|
|
892
|
+
return "".join(
|
|
893
|
+
segment.text for segment in outcome.segments if segment.type == "text" and isinstance(segment.text, str)
|
|
894
|
+
).strip()
|