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
chrys/kernel/_content.py
ADDED
|
@@ -0,0 +1,1866 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
3
|
+
# Contains code adapted from Microsoft Agent Framework (MIT License; see NOTICE).
|
|
4
|
+
|
|
5
|
+
"""Chrys-owned content types."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import base64
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
from collections.abc import Iterable, Mapping, MutableMapping, Sequence
|
|
13
|
+
from copy import deepcopy
|
|
14
|
+
from typing import Any, ClassVar, Final, Literal, TypeGuard, TypeVar, cast
|
|
15
|
+
|
|
16
|
+
from typing_extensions import TypedDict
|
|
17
|
+
|
|
18
|
+
from chrys.foundation.hosted_tools import PRESENTATION_TEXT_SEGMENT_ID_KEY, HostedToolFamily
|
|
19
|
+
from chrys.foundation.reasoning_origin import REASONING_ORIGIN_KEY
|
|
20
|
+
from chrys.foundation.text.model_json import model_json
|
|
21
|
+
|
|
22
|
+
from .exceptions import AdditionItemMismatch, ContentError
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
OPENAI_OUTPUT_MESSAGE_ENVELOPE_KEY: Final[str] = "openai.responses.output_message_envelope"
|
|
27
|
+
# What tells the output items of a Responses stream apart on the function
|
|
28
|
+
# calls it sends, each whole: its position and its item id. Two items are two
|
|
29
|
+
# calls even under one call id, so their calls never merge.
|
|
30
|
+
_RESPONSES_OUTPUT_ITEM_KEYS: Final = ("output_index", "fc_id")
|
|
31
|
+
_ANTHROPIC_REDACTED_THINKING_KEY = "anthropic_redacted_thinking"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# region Content Parsing Utilities
|
|
35
|
+
def _parse_content_list(contents_data: Sequence[Any]) -> list[Content]:
|
|
36
|
+
"""Parse a list of content data into appropriate Content objects.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
contents_data: List of content data (strings, dicts, or already constructed objects)
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
List of Content objects with unknown types logged and ignored
|
|
43
|
+
"""
|
|
44
|
+
contents: list[Content] = []
|
|
45
|
+
for content_data in contents_data:
|
|
46
|
+
if content_data is None:
|
|
47
|
+
continue
|
|
48
|
+
if isinstance(content_data, Content):
|
|
49
|
+
contents.append(content_data)
|
|
50
|
+
continue
|
|
51
|
+
if isinstance(content_data, str):
|
|
52
|
+
contents.append(Content.from_text(text=content_data))
|
|
53
|
+
continue
|
|
54
|
+
try:
|
|
55
|
+
contents.append(Content.from_dict(content_data))
|
|
56
|
+
except ContentError as exc:
|
|
57
|
+
logger.warning(f"Skipping unknown content type or invalid content: {exc}")
|
|
58
|
+
|
|
59
|
+
return contents
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# region Internal Helper functions for unified Content
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def detect_media_type_from_base64(
|
|
66
|
+
*,
|
|
67
|
+
data_bytes: bytes | None = None,
|
|
68
|
+
data_str: str | None = None,
|
|
69
|
+
data_uri: str | None = None,
|
|
70
|
+
) -> str | None:
|
|
71
|
+
"""Detect media type from base64-encoded data by examining magic bytes.
|
|
72
|
+
|
|
73
|
+
This function examines the binary signature (magic bytes) at the start of the data
|
|
74
|
+
to identify common media types. It's reliable for binary formats like images, audio,
|
|
75
|
+
video, and documents, but cannot detect text-based formats like JSON or plain text.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
data_bytes: Raw binary data.
|
|
79
|
+
data_str: Base64-encoded data (without data URI prefix).
|
|
80
|
+
data_uri: Full data URI string (e.g., "data:image/png;base64,iVBORw0KGgo...").
|
|
81
|
+
This will look at the actual data to determine the media_type and not at the URI prefix.
|
|
82
|
+
Will also not compare those two values.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
The detected media type (e.g., 'image/png', 'audio/wav', 'application/pdf')
|
|
86
|
+
or None if the format is not recognized.
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
ValueError: If not exactly 1 of data_bytes, data_str, or data_uri is provided, or if base64 decoding fails.
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
.. code-block:: python
|
|
93
|
+
|
|
94
|
+
from chrys.kernel._content import detect_media_type_from_base64
|
|
95
|
+
|
|
96
|
+
# Detect from base64 string
|
|
97
|
+
base64_data = "iVBORw0KGgo..."
|
|
98
|
+
media_type = detect_media_type_from_base64(base64_data)
|
|
99
|
+
# Returns: "image/png"
|
|
100
|
+
|
|
101
|
+
# Works with data URIs too
|
|
102
|
+
data_uri = "data:image/png;base64,iVBORw0KGgo..."
|
|
103
|
+
media_type = detect_media_type_from_base64(data_uri)
|
|
104
|
+
# Returns: "image/png"
|
|
105
|
+
"""
|
|
106
|
+
data: bytes | None = None
|
|
107
|
+
if data_bytes is not None:
|
|
108
|
+
data = data_bytes
|
|
109
|
+
if data_uri is not None:
|
|
110
|
+
if data is not None:
|
|
111
|
+
raise ValueError("Provide exactly one of data_bytes, data_str, or data_uri.")
|
|
112
|
+
# Remove data URI prefix if present
|
|
113
|
+
if not data_uri.startswith("data:") or "," not in data_uri:
|
|
114
|
+
raise ValueError("Invalid data URI format.")
|
|
115
|
+
prefix, data_str = data_uri.split(",", 1)
|
|
116
|
+
if not prefix.endswith(";base64"):
|
|
117
|
+
raise ValueError("Data URI must use base64 encoding.")
|
|
118
|
+
if data_str is not None:
|
|
119
|
+
if data is not None:
|
|
120
|
+
raise ValueError("Provide exactly one of data_bytes, data_str, or data_uri.")
|
|
121
|
+
try:
|
|
122
|
+
data = base64.b64decode(data_str)
|
|
123
|
+
except Exception as exc:
|
|
124
|
+
raise ValueError("Invalid base64 data provided.") from exc
|
|
125
|
+
if data is None:
|
|
126
|
+
raise ValueError("Provide exactly one of data_bytes, data_str, or data_uri.")
|
|
127
|
+
|
|
128
|
+
# Check magic bytes for common formats
|
|
129
|
+
# Images
|
|
130
|
+
if data.startswith(b"\x89PNG\r\n\x1a\n"):
|
|
131
|
+
return "image/png"
|
|
132
|
+
if data.startswith(b"\xff\xd8\xff"):
|
|
133
|
+
return "image/jpeg"
|
|
134
|
+
if data.startswith((b"GIF87a", b"GIF89a")):
|
|
135
|
+
return "image/gif"
|
|
136
|
+
if data.startswith(b"RIFF") and len(data) > 11 and data[8:12] == b"WEBP":
|
|
137
|
+
return "image/webp"
|
|
138
|
+
if data.startswith(b"BM"):
|
|
139
|
+
return "image/bmp"
|
|
140
|
+
if data.startswith((b"<svg", b"<?xml")):
|
|
141
|
+
return "image/svg+xml"
|
|
142
|
+
|
|
143
|
+
# Documents
|
|
144
|
+
if data.startswith(b"%PDF-"):
|
|
145
|
+
return "application/pdf"
|
|
146
|
+
|
|
147
|
+
# Audio
|
|
148
|
+
if data.startswith(b"RIFF") and len(data) > 11 and data[8:12] == b"WAVE":
|
|
149
|
+
return "audio/wav"
|
|
150
|
+
if data.startswith((b"ID3", b"\xff\xfb", b"\xff\xf3")):
|
|
151
|
+
return "audio/mpeg"
|
|
152
|
+
if data.startswith(b"OggS"):
|
|
153
|
+
return "audio/ogg"
|
|
154
|
+
if data.startswith(b"fLaC"):
|
|
155
|
+
return "audio/flac"
|
|
156
|
+
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _get_data_bytes_as_str(content: Content) -> str | None:
|
|
161
|
+
"""Extract base64 data string from data URI.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
content: The Content instance to extract data from.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
The base64-encoded data as a string, or None if not a data content type.
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
ContentError: If the URI is not a valid data URI.
|
|
171
|
+
"""
|
|
172
|
+
if content.type not in ("data", "uri"):
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
uri = content.uri
|
|
176
|
+
if not uri:
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
if not uri.startswith("data:"):
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
if ";base64," not in uri:
|
|
183
|
+
raise ContentError("Data URI must use base64 encoding")
|
|
184
|
+
|
|
185
|
+
_, data = uri.split(";base64,", 1)
|
|
186
|
+
return data # type: ignore[return-value, no-any-return]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _get_data_bytes(content: Content) -> bytes | None: # pyright: ignore[reportUnusedFunction]
|
|
190
|
+
"""Extract and decode binary data from data URI.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
content: The Content instance to extract data from.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
The decoded binary data, or None if not a data content type.
|
|
197
|
+
|
|
198
|
+
Raises:
|
|
199
|
+
ContentError: If the URI is not a valid data URI or decoding fails.
|
|
200
|
+
"""
|
|
201
|
+
data_str = _get_data_bytes_as_str(content)
|
|
202
|
+
if data_str is None:
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
try:
|
|
206
|
+
return base64.b64decode(data_str)
|
|
207
|
+
except Exception as e:
|
|
208
|
+
raise ContentError(f"Failed to decode base64 data: {e}") from e
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
KNOWN_URI_SCHEMAS: Final[set[str]] = {"http", "https", "ftp", "ftps", "file", "s3", "gs", "azure", "blob"}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _validate_uri(uri: str, media_type: str | None) -> dict[str, Any]:
|
|
215
|
+
"""Validate URI format and return validation result.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
uri: The URI to validate.
|
|
219
|
+
media_type: Optional media type associated with the URI.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
If valid, returns a dict, with "type" key indicating "data" or "uri", along with the uri and media_type.
|
|
223
|
+
"""
|
|
224
|
+
if not uri:
|
|
225
|
+
raise ContentError("URI cannot be empty")
|
|
226
|
+
|
|
227
|
+
# Check for data URI
|
|
228
|
+
if uri.startswith("data:"):
|
|
229
|
+
if "," not in uri:
|
|
230
|
+
raise ContentError("Data URI must contain a comma separating metadata and data")
|
|
231
|
+
prefix, _ = uri.split(",", 1)
|
|
232
|
+
if ";" in prefix:
|
|
233
|
+
parts = prefix.split(";")
|
|
234
|
+
if len(parts) < 2:
|
|
235
|
+
raise ContentError("Invalid data URI format")
|
|
236
|
+
# Check encoding
|
|
237
|
+
encoding = parts[-1]
|
|
238
|
+
if encoding not in ("base64", ""):
|
|
239
|
+
raise ContentError(f"Unsupported data URI encoding: {encoding}")
|
|
240
|
+
if media_type is None:
|
|
241
|
+
# attempt to extract:
|
|
242
|
+
media_type = parts[0][5:] # Remove 'data:'
|
|
243
|
+
return {"type": "data", "uri": uri, "media_type": media_type}
|
|
244
|
+
|
|
245
|
+
# Check for common URI schemes
|
|
246
|
+
if ":" in uri:
|
|
247
|
+
scheme = uri.split(":", 1)[0].lower()
|
|
248
|
+
if not media_type:
|
|
249
|
+
logger.warning("Using URI without media type is not recommended.")
|
|
250
|
+
if scheme not in KNOWN_URI_SCHEMAS:
|
|
251
|
+
logger.info(f"Unknown URI scheme: {scheme}, allowed schemes are {KNOWN_URI_SCHEMAS}.")
|
|
252
|
+
return {"type": "uri", "uri": uri, "media_type": media_type}
|
|
253
|
+
|
|
254
|
+
# No scheme found
|
|
255
|
+
raise ContentError("URI must contain a scheme (e.g., http://, data:, file://)")
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _serialize_value(value: Any, exclude_none: bool) -> Any:
|
|
259
|
+
"""Recursively serialize a value for to_dict."""
|
|
260
|
+
if value is None:
|
|
261
|
+
return None
|
|
262
|
+
if isinstance(value, Content):
|
|
263
|
+
return value.to_dict(exclude_none=exclude_none)
|
|
264
|
+
if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)):
|
|
265
|
+
return [_serialize_value(item, exclude_none) for item in cast(Iterable[Any], value)]
|
|
266
|
+
if isinstance(value, Mapping):
|
|
267
|
+
return {k: _serialize_value(v, exclude_none) for k, v in value.items()} # type: ignore[reportUnknownVariableType]
|
|
268
|
+
if hasattr(value, "to_dict"):
|
|
269
|
+
return value.to_dict() # type: ignore[call-arg]
|
|
270
|
+
return value
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _restore_compaction_annotation_in_additional_properties(
|
|
274
|
+
additional_properties: MutableMapping[str, Any] | None,
|
|
275
|
+
*,
|
|
276
|
+
allow_none: bool = False,
|
|
277
|
+
) -> dict[str, Any] | None:
|
|
278
|
+
if additional_properties is None:
|
|
279
|
+
return None if allow_none else {}
|
|
280
|
+
|
|
281
|
+
return dict(additional_properties)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# region Constants and types
|
|
285
|
+
KNOWN_MEDIA_TYPES = [
|
|
286
|
+
"application/json",
|
|
287
|
+
"application/octet-stream",
|
|
288
|
+
"application/pdf",
|
|
289
|
+
"application/xml",
|
|
290
|
+
"audio/mpeg",
|
|
291
|
+
"audio/mp3",
|
|
292
|
+
"audio/ogg",
|
|
293
|
+
"audio/wav",
|
|
294
|
+
"image/apng",
|
|
295
|
+
"image/avif",
|
|
296
|
+
"image/bmp",
|
|
297
|
+
"image/gif",
|
|
298
|
+
"image/jpeg",
|
|
299
|
+
"image/png",
|
|
300
|
+
"image/svg+xml",
|
|
301
|
+
"image/tiff",
|
|
302
|
+
"image/webp",
|
|
303
|
+
"text/css",
|
|
304
|
+
"text/csv",
|
|
305
|
+
"text/html",
|
|
306
|
+
"text/javascript",
|
|
307
|
+
"text/plain",
|
|
308
|
+
"text/plain;charset=UTF-8",
|
|
309
|
+
"text/xml",
|
|
310
|
+
]
|
|
311
|
+
|
|
312
|
+
# region Unified Content Types
|
|
313
|
+
|
|
314
|
+
ContentType = Literal[
|
|
315
|
+
"text",
|
|
316
|
+
"text_reasoning",
|
|
317
|
+
"data",
|
|
318
|
+
"uri",
|
|
319
|
+
"error",
|
|
320
|
+
"function_call",
|
|
321
|
+
"function_result",
|
|
322
|
+
"usage",
|
|
323
|
+
"hosted_file",
|
|
324
|
+
"hosted_vector_store",
|
|
325
|
+
"code_interpreter_tool_call",
|
|
326
|
+
"code_interpreter_tool_result",
|
|
327
|
+
"image_generation_tool_call",
|
|
328
|
+
"image_generation_tool_result",
|
|
329
|
+
"mcp_server_tool_call",
|
|
330
|
+
"mcp_server_tool_result",
|
|
331
|
+
"search_tool_call",
|
|
332
|
+
"search_tool_result",
|
|
333
|
+
"shell_tool_call",
|
|
334
|
+
"shell_tool_result",
|
|
335
|
+
"shell_command_output",
|
|
336
|
+
"hosted_tool_call",
|
|
337
|
+
"hosted_tool_result",
|
|
338
|
+
]
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class TextSpanRegion(TypedDict, total=False):
|
|
342
|
+
"""TypedDict representation of a text span region annotation."""
|
|
343
|
+
|
|
344
|
+
type: Literal["text_span"]
|
|
345
|
+
start_index: int
|
|
346
|
+
end_index: int
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class Annotation(TypedDict, total=False):
|
|
350
|
+
"""TypedDict representation of an annotation."""
|
|
351
|
+
|
|
352
|
+
type: Literal["citation"]
|
|
353
|
+
title: str
|
|
354
|
+
url: str
|
|
355
|
+
file_id: str
|
|
356
|
+
tool_name: str
|
|
357
|
+
snippet: str | None
|
|
358
|
+
annotated_regions: Sequence[TextSpanRegion]
|
|
359
|
+
additional_properties: dict[str, Any]
|
|
360
|
+
raw_representation: Any
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
ContentT = TypeVar("ContentT", bound="Content")
|
|
364
|
+
|
|
365
|
+
# endregion
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class UsageDetails(TypedDict, total=False, extra_items=int): # type: ignore[call-arg]
|
|
369
|
+
"""A dictionary representing usage details.
|
|
370
|
+
|
|
371
|
+
This is a non-closed dictionary, so any specific provider fields can be added as needed.
|
|
372
|
+
Whenever they can be mapped to standard fields, they will be.
|
|
373
|
+
|
|
374
|
+
Keys:
|
|
375
|
+
input_token_count: The number of input tokens used.
|
|
376
|
+
output_token_count: The number of output tokens generated.
|
|
377
|
+
total_token_count: The total number of tokens (input + output).
|
|
378
|
+
context_input_token_count: The final request's context-window input occupancy.
|
|
379
|
+
context_input_token_estimate: A provider-derived estimate of final input occupancy.
|
|
380
|
+
context_input_token_floor: A provider-derived lower bound for final input occupancy.
|
|
381
|
+
cache_creation_input_token_count: The number of input tokens written to a provider-managed cache.
|
|
382
|
+
cache_read_input_token_count: The number of input tokens served from a provider-managed cache.
|
|
383
|
+
reasoning_output_token_count: The number of output tokens used for reasoning.
|
|
384
|
+
|
|
385
|
+
"""
|
|
386
|
+
|
|
387
|
+
input_token_count: int | None
|
|
388
|
+
output_token_count: int | None
|
|
389
|
+
total_token_count: int | None
|
|
390
|
+
context_input_token_count: int | None
|
|
391
|
+
context_input_token_estimate: int | None
|
|
392
|
+
context_input_token_floor: int | None
|
|
393
|
+
cache_creation_input_token_count: int | None
|
|
394
|
+
cache_read_input_token_count: int | None
|
|
395
|
+
reasoning_output_token_count: int | None
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _is_content_list(value: list[Any]) -> TypeGuard[list[Content]]:
|
|
399
|
+
"""Return whether every item is a Chrys ``Content`` instance."""
|
|
400
|
+
return all(isinstance(item, Content) for item in value)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def add_usage_details(usage1: UsageDetails | None, usage2: UsageDetails | None) -> UsageDetails:
|
|
404
|
+
"""Add two UsageDetails dictionaries by summing all numeric values.
|
|
405
|
+
|
|
406
|
+
If any of the two usage details contains a key with a non-int value, it will be skipped,
|
|
407
|
+
even if the other contains a int-value on that key.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
usage1: First usage details dictionary.
|
|
411
|
+
usage2: Second usage details dictionary.
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
A new UsageDetails dictionary with summed values.
|
|
415
|
+
|
|
416
|
+
Examples:
|
|
417
|
+
.. code-block:: python
|
|
418
|
+
|
|
419
|
+
from chrys.kernel._content import UsageDetails, add_usage_details
|
|
420
|
+
|
|
421
|
+
usage1 = UsageDetails(input_token_count=5, output_token_count=10)
|
|
422
|
+
usage2 = UsageDetails(input_token_count=3, output_token_count=6)
|
|
423
|
+
combined = add_usage_details(usage1, usage2)
|
|
424
|
+
# Result: {'input_token_count': 8, 'output_token_count': 16}
|
|
425
|
+
"""
|
|
426
|
+
if usage1 is None:
|
|
427
|
+
return usage2 or UsageDetails()
|
|
428
|
+
if usage2 is None:
|
|
429
|
+
return usage1
|
|
430
|
+
|
|
431
|
+
result = UsageDetails()
|
|
432
|
+
# Combine all keys from both dictionaries
|
|
433
|
+
all_keys = set(usage1.keys()) | set(usage2.keys())
|
|
434
|
+
for key in all_keys:
|
|
435
|
+
if not isinstance((val1 := usage1.get(key, 0)), (int | None)) or not isinstance(
|
|
436
|
+
(val2 := usage2.get(key, 0)), (int | None)
|
|
437
|
+
):
|
|
438
|
+
logger.warning("Non `int` value found in usage details, skipping.")
|
|
439
|
+
continue
|
|
440
|
+
result[key] = (val1 or 0) + (val2 or 0) # type: ignore[literal-required]
|
|
441
|
+
return result
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def normalize_stream_usage(usages: Sequence[Mapping[str, Any]]) -> UsageDetails | None:
|
|
445
|
+
"""Collapse cumulative usage snapshots from one streamed model call.
|
|
446
|
+
|
|
447
|
+
Streaming providers may emit more than one cumulative usage payload for a
|
|
448
|
+
single request. Summing those snapshots over-counts the request; the
|
|
449
|
+
latest non-null value for each key is the authoritative per-call value.
|
|
450
|
+
|
|
451
|
+
Aggregation *across distinct model calls* remains the responsibility of
|
|
452
|
+
the caller via :func:`add_usage_details`.
|
|
453
|
+
"""
|
|
454
|
+
if not usages:
|
|
455
|
+
return None
|
|
456
|
+
|
|
457
|
+
merged = UsageDetails()
|
|
458
|
+
for usage in usages:
|
|
459
|
+
for key, value in usage.items():
|
|
460
|
+
if value is not None:
|
|
461
|
+
merged[key] = value # type: ignore[literal-required,typeddict-item]
|
|
462
|
+
return merged
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
# region Content Class
|
|
466
|
+
class Content:
|
|
467
|
+
"""Unified content container covering all content variants.
|
|
468
|
+
|
|
469
|
+
This class provides a single unified type that handles all content variants.
|
|
470
|
+
Use the class methods like `Content.from_text()`, `Content.from_data()`,
|
|
471
|
+
`Content.from_uri()`, etc. to create instances.
|
|
472
|
+
"""
|
|
473
|
+
|
|
474
|
+
_SHALLOW_COPY_FIELDS: ClassVar[set[str]] = {"raw_representation"}
|
|
475
|
+
__hash__ = None
|
|
476
|
+
|
|
477
|
+
def __init__(
|
|
478
|
+
self,
|
|
479
|
+
type: ContentType,
|
|
480
|
+
*,
|
|
481
|
+
# Text content fields
|
|
482
|
+
text: str | None = None,
|
|
483
|
+
protected_data: str | None = None,
|
|
484
|
+
# Data/URI content fields
|
|
485
|
+
uri: str | None = None,
|
|
486
|
+
media_type: str | None = None,
|
|
487
|
+
# Error content fields
|
|
488
|
+
message: str | None = None,
|
|
489
|
+
error_code: str | None = None,
|
|
490
|
+
error_details: str | None = None,
|
|
491
|
+
# Usage content fields
|
|
492
|
+
usage_details: UsageDetails | None = None,
|
|
493
|
+
# Function call/result fields
|
|
494
|
+
call_id: str | None = None,
|
|
495
|
+
name: str | None = None,
|
|
496
|
+
arguments: str | Mapping[str, Any] | None = None,
|
|
497
|
+
informational_only: bool = False,
|
|
498
|
+
exception: str | None = None,
|
|
499
|
+
result: Any = None,
|
|
500
|
+
items: Sequence[Content] | None = None,
|
|
501
|
+
# Hosted file/vector store fields
|
|
502
|
+
file_id: str | None = None,
|
|
503
|
+
vector_store_id: str | None = None,
|
|
504
|
+
# Code interpreter tool fields
|
|
505
|
+
inputs: list[Content] | None = None,
|
|
506
|
+
outputs: list[Content] | Any | None = None,
|
|
507
|
+
# Image generation tool fields
|
|
508
|
+
image_id: str | None = None,
|
|
509
|
+
# Shell tool fields
|
|
510
|
+
commands: list[str] | None = None,
|
|
511
|
+
timeout_ms: int | None = None,
|
|
512
|
+
max_output_length: int | None = None,
|
|
513
|
+
status: str | None = None,
|
|
514
|
+
# Shell command output fields
|
|
515
|
+
stdout: str | None = None,
|
|
516
|
+
stderr: str | None = None,
|
|
517
|
+
exit_code: int | None = None,
|
|
518
|
+
timed_out: bool | None = None,
|
|
519
|
+
# MCP server tool fields
|
|
520
|
+
tool_name: str | None = None,
|
|
521
|
+
server_name: str | None = None,
|
|
522
|
+
output: Any = None,
|
|
523
|
+
# Server-issued item identity (e.g. Responses reasoning ``rs_*`` ids)
|
|
524
|
+
id: str | None = None,
|
|
525
|
+
# Provider-hosted tool fields
|
|
526
|
+
provider_hosted: bool = False,
|
|
527
|
+
hosted_family: str | None = None,
|
|
528
|
+
hosted_provider: str | None = None,
|
|
529
|
+
provider_item_type: str | None = None,
|
|
530
|
+
provider_item_id: str | None = None,
|
|
531
|
+
provider_phase: str | None = None,
|
|
532
|
+
provider_status: str | None = None,
|
|
533
|
+
retry_safety: str | None = None,
|
|
534
|
+
# Common fields
|
|
535
|
+
annotations: Sequence[Annotation] | None = None,
|
|
536
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
537
|
+
raw_representation: Any | None = None,
|
|
538
|
+
) -> None:
|
|
539
|
+
"""Create a content instance.
|
|
540
|
+
|
|
541
|
+
Prefer using the classmethod constructors like `Content.from_text()` instead of calling __init__ directly.
|
|
542
|
+
"""
|
|
543
|
+
self.type = type
|
|
544
|
+
self.annotations = annotations
|
|
545
|
+
self.additional_properties: dict[str, Any] = (
|
|
546
|
+
_restore_compaction_annotation_in_additional_properties(additional_properties) or {}
|
|
547
|
+
)
|
|
548
|
+
self.raw_representation = raw_representation
|
|
549
|
+
|
|
550
|
+
# Set all content-specific attributes
|
|
551
|
+
self.text = text
|
|
552
|
+
self.protected_data = protected_data
|
|
553
|
+
self.uri = uri
|
|
554
|
+
self.media_type = media_type
|
|
555
|
+
self.message = message
|
|
556
|
+
self.error_code = error_code
|
|
557
|
+
self.error_details = error_details
|
|
558
|
+
self.usage_details = usage_details
|
|
559
|
+
self.call_id = call_id
|
|
560
|
+
self.name = name
|
|
561
|
+
self.arguments = arguments
|
|
562
|
+
self.informational_only = informational_only or type == "mcp_server_tool_call"
|
|
563
|
+
self.exception = exception
|
|
564
|
+
self.result = result
|
|
565
|
+
self.items = items
|
|
566
|
+
self.file_id = file_id
|
|
567
|
+
self.vector_store_id = vector_store_id
|
|
568
|
+
self.inputs = inputs
|
|
569
|
+
self.outputs = outputs
|
|
570
|
+
self.image_id = image_id
|
|
571
|
+
self.commands = commands
|
|
572
|
+
self.timeout_ms = timeout_ms
|
|
573
|
+
self.max_output_length = max_output_length
|
|
574
|
+
self.status = status
|
|
575
|
+
self.stdout = stdout
|
|
576
|
+
self.stderr = stderr
|
|
577
|
+
self.exit_code = exit_code
|
|
578
|
+
self.timed_out = timed_out
|
|
579
|
+
self.tool_name = tool_name
|
|
580
|
+
self.server_name = server_name
|
|
581
|
+
self.output = output
|
|
582
|
+
self.id = id
|
|
583
|
+
self.provider_hosted = provider_hosted
|
|
584
|
+
self.hosted_family = hosted_family
|
|
585
|
+
self.hosted_provider = hosted_provider
|
|
586
|
+
self.provider_item_type = provider_item_type
|
|
587
|
+
self.provider_item_id = provider_item_id
|
|
588
|
+
self.provider_phase = provider_phase
|
|
589
|
+
self.provider_status = provider_status
|
|
590
|
+
self.retry_safety = retry_safety
|
|
591
|
+
|
|
592
|
+
def __deepcopy__(self, memo: dict[int, Any]) -> Content:
|
|
593
|
+
"""Create a deep copy, preserving ``_SHALLOW_COPY_FIELDS`` by reference.
|
|
594
|
+
|
|
595
|
+
Fields listed in ``_SHALLOW_COPY_FIELDS`` may contain LLM SDK objects
|
|
596
|
+
(e.g., proto/gRPC responses) that are not safe to deep-copy.
|
|
597
|
+
"""
|
|
598
|
+
cls = type(self)
|
|
599
|
+
result = cls.__new__(cls)
|
|
600
|
+
memo[id(self)] = result
|
|
601
|
+
shallow = cls._SHALLOW_COPY_FIELDS
|
|
602
|
+
for k, v in self.__dict__.items():
|
|
603
|
+
if k in shallow:
|
|
604
|
+
object.__setattr__(result, k, v)
|
|
605
|
+
else:
|
|
606
|
+
object.__setattr__(result, k, deepcopy(v, memo))
|
|
607
|
+
return result
|
|
608
|
+
|
|
609
|
+
@classmethod
|
|
610
|
+
def from_text(
|
|
611
|
+
cls: type[ContentT],
|
|
612
|
+
text: str,
|
|
613
|
+
*,
|
|
614
|
+
annotations: Sequence[Annotation] | None = None,
|
|
615
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
616
|
+
raw_representation: Any = None,
|
|
617
|
+
) -> ContentT:
|
|
618
|
+
"""Create text content."""
|
|
619
|
+
return cls(
|
|
620
|
+
"text",
|
|
621
|
+
text=text,
|
|
622
|
+
annotations=annotations,
|
|
623
|
+
additional_properties=additional_properties,
|
|
624
|
+
raw_representation=raw_representation,
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
@classmethod
|
|
628
|
+
def from_text_reasoning(
|
|
629
|
+
cls: type[ContentT],
|
|
630
|
+
*,
|
|
631
|
+
id: str | None = None,
|
|
632
|
+
text: str | None = None,
|
|
633
|
+
protected_data: str | None = None,
|
|
634
|
+
annotations: Sequence[Annotation] | None = None,
|
|
635
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
636
|
+
raw_representation: Any = None,
|
|
637
|
+
) -> ContentT:
|
|
638
|
+
"""Create text reasoning content."""
|
|
639
|
+
return cls(
|
|
640
|
+
"text_reasoning",
|
|
641
|
+
id=id,
|
|
642
|
+
text=text,
|
|
643
|
+
protected_data=protected_data,
|
|
644
|
+
annotations=annotations,
|
|
645
|
+
additional_properties=additional_properties,
|
|
646
|
+
raw_representation=raw_representation,
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
@classmethod
|
|
650
|
+
def from_data(
|
|
651
|
+
cls: type[ContentT],
|
|
652
|
+
data: bytes,
|
|
653
|
+
media_type: str,
|
|
654
|
+
*,
|
|
655
|
+
annotations: Sequence[Annotation] | None = None,
|
|
656
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
657
|
+
raw_representation: Any = None,
|
|
658
|
+
) -> ContentT:
|
|
659
|
+
r"""Create data content from raw binary data.
|
|
660
|
+
|
|
661
|
+
Use this to create content from binary data (images, audio, documents, etc.).
|
|
662
|
+
The data will be automatically base64-encoded into a data URI.
|
|
663
|
+
|
|
664
|
+
Args:
|
|
665
|
+
data: Raw binary data as bytes. This should be the actual binary data,
|
|
666
|
+
not a base64-encoded string. If you have a base64 string,
|
|
667
|
+
decode it first: base64.b64decode(base64_string)
|
|
668
|
+
media_type: The MIME type of the data (e.g., "image/png", "application/pdf").
|
|
669
|
+
If you don't know the media type and have base64 data, you can detect it in some cases:
|
|
670
|
+
|
|
671
|
+
.. code-block:: python
|
|
672
|
+
|
|
673
|
+
from chrys.kernel._content import detect_media_type_from_base64, Content
|
|
674
|
+
|
|
675
|
+
media_type = detect_media_type_from_base64(base64_string)
|
|
676
|
+
if media_type is None:
|
|
677
|
+
raise ValueError("Could not detect media type")
|
|
678
|
+
data_bytes = base64.b64decode(base64_string)
|
|
679
|
+
content = Content.from_data(data=data_bytes, media_type=media_type)
|
|
680
|
+
|
|
681
|
+
Keyword Args:
|
|
682
|
+
annotations: Optional annotations associated with the content.
|
|
683
|
+
additional_properties: Optional additional properties.
|
|
684
|
+
raw_representation: Optional raw representation from an underlying implementation.
|
|
685
|
+
|
|
686
|
+
Returns:
|
|
687
|
+
A Content instance with type="data".
|
|
688
|
+
|
|
689
|
+
Raises:
|
|
690
|
+
TypeError: If data is not bytes.
|
|
691
|
+
|
|
692
|
+
Examples:
|
|
693
|
+
.. code-block:: python
|
|
694
|
+
|
|
695
|
+
from chrys.kernel._content import Content, detect_media_type_from_base64
|
|
696
|
+
import base64
|
|
697
|
+
|
|
698
|
+
# Create from raw binary data with known media type
|
|
699
|
+
image_bytes = b"\x89PNG\r\n\x1a\n..."
|
|
700
|
+
content = Content.from_data(data=image_bytes, media_type="image/png")
|
|
701
|
+
|
|
702
|
+
# If you have a base64 string and need to detect media type
|
|
703
|
+
base64_string = "iVBORw0KGgo..."
|
|
704
|
+
media_type = detect_media_type_from_base64(base64_string)
|
|
705
|
+
if media_type is None:
|
|
706
|
+
raise ValueError("Unknown media type")
|
|
707
|
+
image_bytes = base64.b64decode(base64_string)
|
|
708
|
+
content = Content.from_data(data=image_bytes, media_type=media_type)
|
|
709
|
+
"""
|
|
710
|
+
try:
|
|
711
|
+
encoded_data = base64.b64encode(data).decode("utf-8")
|
|
712
|
+
except TypeError as e:
|
|
713
|
+
raise TypeError(
|
|
714
|
+
"Could not encode data to base64. Ensure 'data' is of type bytes.Or another b64encode compatible type."
|
|
715
|
+
) from e
|
|
716
|
+
return cls(
|
|
717
|
+
"data",
|
|
718
|
+
uri=f"data:{media_type};base64,{encoded_data}",
|
|
719
|
+
media_type=media_type,
|
|
720
|
+
annotations=annotations,
|
|
721
|
+
additional_properties=additional_properties,
|
|
722
|
+
raw_representation=raw_representation,
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
@classmethod
|
|
726
|
+
def from_uri(
|
|
727
|
+
cls: type[ContentT],
|
|
728
|
+
uri: str,
|
|
729
|
+
*,
|
|
730
|
+
media_type: str | None = None,
|
|
731
|
+
annotations: Sequence[Annotation] | None = None,
|
|
732
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
733
|
+
raw_representation: Any = None,
|
|
734
|
+
) -> ContentT:
|
|
735
|
+
"""Create content from a URI, can be both data URI or external URI.
|
|
736
|
+
|
|
737
|
+
Use this when you already have a properly formed data URI
|
|
738
|
+
(e.g., "data:image/png;base64,iVBORw0KGgo...").
|
|
739
|
+
Or when you receive a link to a online resource (e.g., "https://example.com/image.png").
|
|
740
|
+
|
|
741
|
+
Args:
|
|
742
|
+
uri: A URI string,
|
|
743
|
+
that either includes the media type and base64-encoded data,
|
|
744
|
+
or a valid URL to an external resource.
|
|
745
|
+
|
|
746
|
+
Keyword Args:
|
|
747
|
+
media_type: The MIME type of the data (e.g., "image/png", "application/pdf").
|
|
748
|
+
This is optional but recommended for external URIs.
|
|
749
|
+
annotations: Optional annotations associated with the content.
|
|
750
|
+
additional_properties: Optional additional properties.
|
|
751
|
+
raw_representation: Optional raw representation from an underlying implementation.
|
|
752
|
+
|
|
753
|
+
Returns:
|
|
754
|
+
A Content instance with type="data" for data URIs or type="uri" for external URIs.
|
|
755
|
+
|
|
756
|
+
Raises:
|
|
757
|
+
ContentError: If the URI is not valid.
|
|
758
|
+
|
|
759
|
+
Examples:
|
|
760
|
+
.. code-block:: python
|
|
761
|
+
|
|
762
|
+
from chrys.kernel._content import Content
|
|
763
|
+
|
|
764
|
+
# Create from a data URI
|
|
765
|
+
content = Content.from_uri(uri="data:image/png;base64,iVBORw0KGgo...", media_type="image/png")
|
|
766
|
+
assert content.type == "data"
|
|
767
|
+
|
|
768
|
+
# Create from an external URI
|
|
769
|
+
content = Content.from_uri(uri="https://example.com/image.png", media_type="image/png")
|
|
770
|
+
assert content.type == "uri"
|
|
771
|
+
|
|
772
|
+
# When receiving a raw already encode data string, you can do this:
|
|
773
|
+
raw_base64_string = "iVBORw0KGgo..."
|
|
774
|
+
content = Content.from_uri(
|
|
775
|
+
uri=f"data:{(detect_media_type_from_base64(data_str=raw_base64_string) or 'image/png')};base64,{
|
|
776
|
+
raw_base64_string
|
|
777
|
+
}"
|
|
778
|
+
)
|
|
779
|
+
"""
|
|
780
|
+
return cls(
|
|
781
|
+
**_validate_uri(uri, media_type),
|
|
782
|
+
annotations=annotations,
|
|
783
|
+
additional_properties=additional_properties,
|
|
784
|
+
raw_representation=raw_representation,
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
@classmethod
|
|
788
|
+
def from_error(
|
|
789
|
+
cls: type[ContentT],
|
|
790
|
+
*,
|
|
791
|
+
message: str | None = None,
|
|
792
|
+
error_code: str | None = None,
|
|
793
|
+
error_details: str | None = None,
|
|
794
|
+
annotations: Sequence[Annotation] | None = None,
|
|
795
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
796
|
+
raw_representation: Any = None,
|
|
797
|
+
) -> ContentT:
|
|
798
|
+
"""Create error content."""
|
|
799
|
+
return cls(
|
|
800
|
+
"error",
|
|
801
|
+
message=message,
|
|
802
|
+
error_code=error_code,
|
|
803
|
+
error_details=error_details,
|
|
804
|
+
annotations=annotations,
|
|
805
|
+
additional_properties=additional_properties,
|
|
806
|
+
raw_representation=raw_representation,
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
@classmethod
|
|
810
|
+
def from_function_call(
|
|
811
|
+
cls: type[ContentT],
|
|
812
|
+
call_id: str,
|
|
813
|
+
name: str,
|
|
814
|
+
*,
|
|
815
|
+
arguments: str | Mapping[str, Any] | None = None,
|
|
816
|
+
informational_only: bool = False,
|
|
817
|
+
exception: str | None = None,
|
|
818
|
+
annotations: Sequence[Annotation] | None = None,
|
|
819
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
820
|
+
raw_representation: Any = None,
|
|
821
|
+
) -> ContentT:
|
|
822
|
+
"""Create function call content.
|
|
823
|
+
|
|
824
|
+
``informational_only=True`` preserves a provider-hosted call in the
|
|
825
|
+
transcript without authorizing the local tool loop to execute it. The
|
|
826
|
+
flag is serialized only when true so older sessions retain their wire
|
|
827
|
+
shape; sessions containing a true flag require a build that supports
|
|
828
|
+
this field and are not downgrade-compatible with older Chrys builds.
|
|
829
|
+
"""
|
|
830
|
+
return cls(
|
|
831
|
+
"function_call",
|
|
832
|
+
call_id=call_id,
|
|
833
|
+
name=name,
|
|
834
|
+
arguments=arguments,
|
|
835
|
+
informational_only=informational_only,
|
|
836
|
+
exception=exception,
|
|
837
|
+
annotations=annotations,
|
|
838
|
+
additional_properties=additional_properties,
|
|
839
|
+
raw_representation=raw_representation,
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
@classmethod
|
|
843
|
+
def from_function_result(
|
|
844
|
+
cls: type[ContentT],
|
|
845
|
+
call_id: str | None,
|
|
846
|
+
*,
|
|
847
|
+
result: Any = None,
|
|
848
|
+
exception: str | None = None,
|
|
849
|
+
annotations: Sequence[Annotation] | None = None,
|
|
850
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
851
|
+
raw_representation: Any = None,
|
|
852
|
+
) -> ContentT:
|
|
853
|
+
"""Create function result content.
|
|
854
|
+
|
|
855
|
+
All tool output is represented uniformly as Content items in the
|
|
856
|
+
``items`` field. The ``result`` field is populated with the concatenated
|
|
857
|
+
text from text items for backwards compatibility.
|
|
858
|
+
|
|
859
|
+
Args:
|
|
860
|
+
call_id: The ID of the function call this result corresponds to.
|
|
861
|
+
|
|
862
|
+
Keyword Args:
|
|
863
|
+
result: The tool output. Accepts a ``list[Content]`` (the canonical
|
|
864
|
+
form produced by :meth:`~FunctionTool.parse_result`), a plain
|
|
865
|
+
``str``, or any other value (which is stringified).
|
|
866
|
+
exception: The exception message if the function call failed.
|
|
867
|
+
annotations: Optional annotations for the content.
|
|
868
|
+
additional_properties: Optional additional properties.
|
|
869
|
+
raw_representation: Optional raw representation from the provider.
|
|
870
|
+
"""
|
|
871
|
+
if isinstance(result, list):
|
|
872
|
+
if _is_content_list(result):
|
|
873
|
+
items_list: list[Content] = list(result)
|
|
874
|
+
else:
|
|
875
|
+
items_list = [Content.from_text(str(result))] # type: ignore[reportUnknownArgumentType]
|
|
876
|
+
elif isinstance(result, str):
|
|
877
|
+
items_list = [Content.from_text(result)]
|
|
878
|
+
elif result is not None:
|
|
879
|
+
try:
|
|
880
|
+
text = model_json(result, default=str)
|
|
881
|
+
except TypeError, ValueError:
|
|
882
|
+
text = str(result)
|
|
883
|
+
items_list = [Content.from_text(text)]
|
|
884
|
+
else:
|
|
885
|
+
items_list = [Content.from_text("")]
|
|
886
|
+
|
|
887
|
+
text_parts = [c.text for c in items_list if c.type == "text" and c.text]
|
|
888
|
+
text_result = "\n".join(text_parts) if text_parts else ""
|
|
889
|
+
|
|
890
|
+
return cls(
|
|
891
|
+
"function_result",
|
|
892
|
+
call_id=call_id,
|
|
893
|
+
result=text_result,
|
|
894
|
+
items=items_list,
|
|
895
|
+
exception=exception,
|
|
896
|
+
annotations=annotations,
|
|
897
|
+
additional_properties=additional_properties,
|
|
898
|
+
raw_representation=raw_representation,
|
|
899
|
+
)
|
|
900
|
+
|
|
901
|
+
@classmethod
|
|
902
|
+
def from_search_tool_call(
|
|
903
|
+
cls: type[ContentT],
|
|
904
|
+
call_id: str,
|
|
905
|
+
*,
|
|
906
|
+
tool_name: str,
|
|
907
|
+
arguments: str | Mapping[str, Any] | None = None,
|
|
908
|
+
status: str | None = None,
|
|
909
|
+
hosted_family: str = HostedToolFamily.SEARCH,
|
|
910
|
+
hosted_provider: str | None = None,
|
|
911
|
+
provider_item_type: str | None = None,
|
|
912
|
+
provider_item_id: str | None = None,
|
|
913
|
+
provider_phase: str | None = None,
|
|
914
|
+
provider_status: str | None = None,
|
|
915
|
+
retry_safety: str | None = None,
|
|
916
|
+
annotations: Sequence[Annotation] | None = None,
|
|
917
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
918
|
+
raw_representation: Any = None,
|
|
919
|
+
) -> ContentT:
|
|
920
|
+
"""Create search tool call content."""
|
|
921
|
+
return cls(
|
|
922
|
+
"search_tool_call",
|
|
923
|
+
call_id=call_id,
|
|
924
|
+
tool_name=tool_name,
|
|
925
|
+
arguments=arguments,
|
|
926
|
+
status=status,
|
|
927
|
+
provider_hosted=True,
|
|
928
|
+
hosted_family=hosted_family,
|
|
929
|
+
hosted_provider=hosted_provider,
|
|
930
|
+
provider_item_type=provider_item_type,
|
|
931
|
+
provider_item_id=provider_item_id,
|
|
932
|
+
provider_phase=provider_phase,
|
|
933
|
+
provider_status=provider_status if provider_status is not None else status,
|
|
934
|
+
retry_safety=retry_safety,
|
|
935
|
+
annotations=annotations,
|
|
936
|
+
additional_properties=additional_properties,
|
|
937
|
+
raw_representation=raw_representation,
|
|
938
|
+
)
|
|
939
|
+
|
|
940
|
+
@classmethod
|
|
941
|
+
def from_search_tool_result(
|
|
942
|
+
cls: type[ContentT],
|
|
943
|
+
call_id: str,
|
|
944
|
+
*,
|
|
945
|
+
tool_name: str,
|
|
946
|
+
result: Any = None,
|
|
947
|
+
items: Sequence[Content] | None = None,
|
|
948
|
+
status: str | None = None,
|
|
949
|
+
hosted_family: str = HostedToolFamily.SEARCH,
|
|
950
|
+
hosted_provider: str | None = None,
|
|
951
|
+
provider_item_type: str | None = None,
|
|
952
|
+
provider_item_id: str | None = None,
|
|
953
|
+
provider_phase: str | None = None,
|
|
954
|
+
provider_status: str | None = None,
|
|
955
|
+
retry_safety: str | None = None,
|
|
956
|
+
annotations: Sequence[Annotation] | None = None,
|
|
957
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
958
|
+
raw_representation: Any = None,
|
|
959
|
+
) -> ContentT:
|
|
960
|
+
"""Create search tool result content."""
|
|
961
|
+
return cls(
|
|
962
|
+
"search_tool_result",
|
|
963
|
+
call_id=call_id,
|
|
964
|
+
tool_name=tool_name,
|
|
965
|
+
result=result,
|
|
966
|
+
items=list(items) if items is not None else None,
|
|
967
|
+
status=status,
|
|
968
|
+
provider_hosted=True,
|
|
969
|
+
hosted_family=hosted_family,
|
|
970
|
+
hosted_provider=hosted_provider,
|
|
971
|
+
provider_item_type=provider_item_type,
|
|
972
|
+
provider_item_id=provider_item_id,
|
|
973
|
+
provider_phase=provider_phase,
|
|
974
|
+
provider_status=provider_status if provider_status is not None else status,
|
|
975
|
+
retry_safety=retry_safety,
|
|
976
|
+
annotations=annotations,
|
|
977
|
+
additional_properties=additional_properties,
|
|
978
|
+
raw_representation=raw_representation,
|
|
979
|
+
)
|
|
980
|
+
|
|
981
|
+
@classmethod
|
|
982
|
+
def from_hosted_tool_call(
|
|
983
|
+
cls: type[ContentT],
|
|
984
|
+
call_id: str | None,
|
|
985
|
+
*,
|
|
986
|
+
tool_name: str,
|
|
987
|
+
arguments: Any = None,
|
|
988
|
+
status: str | None = None,
|
|
989
|
+
hosted_family: str = HostedToolFamily.GENERIC,
|
|
990
|
+
hosted_provider: str | None = None,
|
|
991
|
+
provider_item_type: str | None = None,
|
|
992
|
+
provider_item_id: str | None = None,
|
|
993
|
+
provider_phase: str | None = None,
|
|
994
|
+
provider_status: str | None = None,
|
|
995
|
+
retry_safety: str | None = None,
|
|
996
|
+
annotations: Sequence[Annotation] | None = None,
|
|
997
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
998
|
+
raw_representation: Any = None,
|
|
999
|
+
) -> ContentT:
|
|
1000
|
+
"""Create generic provider-hosted tool call content."""
|
|
1001
|
+
return cls(
|
|
1002
|
+
"hosted_tool_call",
|
|
1003
|
+
call_id=call_id,
|
|
1004
|
+
tool_name=tool_name,
|
|
1005
|
+
arguments=arguments,
|
|
1006
|
+
status=status,
|
|
1007
|
+
provider_hosted=True,
|
|
1008
|
+
hosted_family=hosted_family,
|
|
1009
|
+
hosted_provider=hosted_provider,
|
|
1010
|
+
provider_item_type=provider_item_type,
|
|
1011
|
+
provider_item_id=provider_item_id,
|
|
1012
|
+
provider_phase=provider_phase,
|
|
1013
|
+
provider_status=provider_status if provider_status is not None else status,
|
|
1014
|
+
retry_safety=retry_safety,
|
|
1015
|
+
annotations=annotations,
|
|
1016
|
+
additional_properties=additional_properties,
|
|
1017
|
+
raw_representation=raw_representation,
|
|
1018
|
+
)
|
|
1019
|
+
|
|
1020
|
+
@classmethod
|
|
1021
|
+
def from_hosted_tool_result(
|
|
1022
|
+
cls: type[ContentT],
|
|
1023
|
+
call_id: str | None,
|
|
1024
|
+
*,
|
|
1025
|
+
tool_name: str | None = None,
|
|
1026
|
+
result: Any = None,
|
|
1027
|
+
items: Sequence[Content] | None = None,
|
|
1028
|
+
status: str | None = None,
|
|
1029
|
+
hosted_family: str = HostedToolFamily.GENERIC,
|
|
1030
|
+
hosted_provider: str | None = None,
|
|
1031
|
+
provider_item_type: str | None = None,
|
|
1032
|
+
provider_item_id: str | None = None,
|
|
1033
|
+
provider_phase: str | None = None,
|
|
1034
|
+
provider_status: str | None = None,
|
|
1035
|
+
retry_safety: str | None = None,
|
|
1036
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1037
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1038
|
+
raw_representation: Any = None,
|
|
1039
|
+
) -> ContentT:
|
|
1040
|
+
"""Create generic provider-hosted tool result content."""
|
|
1041
|
+
return cls(
|
|
1042
|
+
"hosted_tool_result",
|
|
1043
|
+
call_id=call_id,
|
|
1044
|
+
tool_name=tool_name,
|
|
1045
|
+
result=result,
|
|
1046
|
+
items=list(items) if items is not None else None,
|
|
1047
|
+
status=status,
|
|
1048
|
+
provider_hosted=True,
|
|
1049
|
+
hosted_family=hosted_family,
|
|
1050
|
+
hosted_provider=hosted_provider,
|
|
1051
|
+
provider_item_type=provider_item_type,
|
|
1052
|
+
provider_item_id=provider_item_id,
|
|
1053
|
+
provider_phase=provider_phase,
|
|
1054
|
+
provider_status=provider_status if provider_status is not None else status,
|
|
1055
|
+
retry_safety=retry_safety,
|
|
1056
|
+
annotations=annotations,
|
|
1057
|
+
additional_properties=additional_properties,
|
|
1058
|
+
raw_representation=raw_representation,
|
|
1059
|
+
)
|
|
1060
|
+
|
|
1061
|
+
@classmethod
|
|
1062
|
+
def from_usage(
|
|
1063
|
+
cls: type[ContentT],
|
|
1064
|
+
usage_details: UsageDetails,
|
|
1065
|
+
*,
|
|
1066
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1067
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1068
|
+
raw_representation: Any = None,
|
|
1069
|
+
) -> ContentT:
|
|
1070
|
+
"""Create usage content."""
|
|
1071
|
+
return cls(
|
|
1072
|
+
"usage",
|
|
1073
|
+
usage_details=usage_details,
|
|
1074
|
+
annotations=annotations,
|
|
1075
|
+
additional_properties=additional_properties,
|
|
1076
|
+
raw_representation=raw_representation,
|
|
1077
|
+
)
|
|
1078
|
+
|
|
1079
|
+
@classmethod
|
|
1080
|
+
def from_hosted_file(
|
|
1081
|
+
cls: type[ContentT],
|
|
1082
|
+
file_id: str,
|
|
1083
|
+
*,
|
|
1084
|
+
media_type: str | None = None,
|
|
1085
|
+
name: str | None = None,
|
|
1086
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1087
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1088
|
+
raw_representation: Any = None,
|
|
1089
|
+
) -> ContentT:
|
|
1090
|
+
"""Create hosted file content."""
|
|
1091
|
+
return cls(
|
|
1092
|
+
"hosted_file",
|
|
1093
|
+
file_id=file_id,
|
|
1094
|
+
media_type=media_type,
|
|
1095
|
+
name=name,
|
|
1096
|
+
annotations=annotations,
|
|
1097
|
+
additional_properties=additional_properties,
|
|
1098
|
+
raw_representation=raw_representation,
|
|
1099
|
+
)
|
|
1100
|
+
|
|
1101
|
+
@classmethod
|
|
1102
|
+
def from_hosted_vector_store(
|
|
1103
|
+
cls: type[ContentT],
|
|
1104
|
+
vector_store_id: str,
|
|
1105
|
+
*,
|
|
1106
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1107
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1108
|
+
raw_representation: Any = None,
|
|
1109
|
+
) -> ContentT:
|
|
1110
|
+
"""Create hosted vector store content."""
|
|
1111
|
+
return cls(
|
|
1112
|
+
"hosted_vector_store",
|
|
1113
|
+
vector_store_id=vector_store_id,
|
|
1114
|
+
annotations=annotations,
|
|
1115
|
+
additional_properties=additional_properties,
|
|
1116
|
+
raw_representation=raw_representation,
|
|
1117
|
+
)
|
|
1118
|
+
|
|
1119
|
+
@classmethod
|
|
1120
|
+
def from_code_interpreter_tool_call(
|
|
1121
|
+
cls: type[ContentT],
|
|
1122
|
+
*,
|
|
1123
|
+
call_id: str | None = None,
|
|
1124
|
+
inputs: Sequence[Content] | None = None,
|
|
1125
|
+
hosted_provider: str | None = None,
|
|
1126
|
+
provider_item_type: str | None = None,
|
|
1127
|
+
provider_item_id: str | None = None,
|
|
1128
|
+
provider_phase: str | None = None,
|
|
1129
|
+
provider_status: str | None = None,
|
|
1130
|
+
retry_safety: str | None = None,
|
|
1131
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1132
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1133
|
+
raw_representation: Any = None,
|
|
1134
|
+
) -> ContentT:
|
|
1135
|
+
"""Create code interpreter tool call content."""
|
|
1136
|
+
return cls(
|
|
1137
|
+
"code_interpreter_tool_call",
|
|
1138
|
+
call_id=call_id,
|
|
1139
|
+
inputs=list(inputs) if inputs is not None else None,
|
|
1140
|
+
provider_hosted=True,
|
|
1141
|
+
hosted_family=HostedToolFamily.CODE,
|
|
1142
|
+
hosted_provider=hosted_provider,
|
|
1143
|
+
provider_item_type=provider_item_type,
|
|
1144
|
+
provider_item_id=provider_item_id,
|
|
1145
|
+
provider_phase=provider_phase,
|
|
1146
|
+
provider_status=provider_status,
|
|
1147
|
+
retry_safety=retry_safety,
|
|
1148
|
+
annotations=annotations,
|
|
1149
|
+
additional_properties=additional_properties,
|
|
1150
|
+
raw_representation=raw_representation,
|
|
1151
|
+
)
|
|
1152
|
+
|
|
1153
|
+
@classmethod
|
|
1154
|
+
def from_code_interpreter_tool_result(
|
|
1155
|
+
cls: type[ContentT],
|
|
1156
|
+
*,
|
|
1157
|
+
call_id: str | None = None,
|
|
1158
|
+
outputs: Sequence[Content] | None = None,
|
|
1159
|
+
hosted_provider: str | None = None,
|
|
1160
|
+
provider_item_type: str | None = None,
|
|
1161
|
+
provider_item_id: str | None = None,
|
|
1162
|
+
provider_phase: str | None = None,
|
|
1163
|
+
provider_status: str | None = None,
|
|
1164
|
+
retry_safety: str | None = None,
|
|
1165
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1166
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1167
|
+
raw_representation: Any = None,
|
|
1168
|
+
) -> ContentT:
|
|
1169
|
+
"""Create code interpreter tool result content."""
|
|
1170
|
+
return cls(
|
|
1171
|
+
"code_interpreter_tool_result",
|
|
1172
|
+
call_id=call_id,
|
|
1173
|
+
outputs=list(outputs) if outputs is not None else None,
|
|
1174
|
+
provider_hosted=True,
|
|
1175
|
+
hosted_family=HostedToolFamily.CODE,
|
|
1176
|
+
hosted_provider=hosted_provider,
|
|
1177
|
+
provider_item_type=provider_item_type,
|
|
1178
|
+
provider_item_id=provider_item_id,
|
|
1179
|
+
provider_phase=provider_phase,
|
|
1180
|
+
provider_status=provider_status,
|
|
1181
|
+
retry_safety=retry_safety,
|
|
1182
|
+
annotations=annotations,
|
|
1183
|
+
additional_properties=additional_properties,
|
|
1184
|
+
raw_representation=raw_representation,
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1187
|
+
@classmethod
|
|
1188
|
+
def from_image_generation_tool_call(
|
|
1189
|
+
cls: type[ContentT],
|
|
1190
|
+
*,
|
|
1191
|
+
image_id: str | None = None,
|
|
1192
|
+
hosted_provider: str | None = None,
|
|
1193
|
+
provider_item_type: str | None = None,
|
|
1194
|
+
provider_item_id: str | None = None,
|
|
1195
|
+
provider_phase: str | None = None,
|
|
1196
|
+
provider_status: str | None = None,
|
|
1197
|
+
retry_safety: str | None = None,
|
|
1198
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1199
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1200
|
+
raw_representation: Any = None,
|
|
1201
|
+
) -> ContentT:
|
|
1202
|
+
"""Create image generation tool call content."""
|
|
1203
|
+
return cls(
|
|
1204
|
+
"image_generation_tool_call",
|
|
1205
|
+
image_id=image_id,
|
|
1206
|
+
provider_hosted=True,
|
|
1207
|
+
hosted_family=HostedToolFamily.IMAGE,
|
|
1208
|
+
hosted_provider=hosted_provider,
|
|
1209
|
+
provider_item_type=provider_item_type,
|
|
1210
|
+
provider_item_id=provider_item_id,
|
|
1211
|
+
provider_phase=provider_phase,
|
|
1212
|
+
provider_status=provider_status,
|
|
1213
|
+
retry_safety=retry_safety,
|
|
1214
|
+
annotations=annotations,
|
|
1215
|
+
additional_properties=additional_properties,
|
|
1216
|
+
raw_representation=raw_representation,
|
|
1217
|
+
)
|
|
1218
|
+
|
|
1219
|
+
@classmethod
|
|
1220
|
+
def from_image_generation_tool_result(
|
|
1221
|
+
cls: type[ContentT],
|
|
1222
|
+
*,
|
|
1223
|
+
image_id: str | None = None,
|
|
1224
|
+
outputs: Any = None,
|
|
1225
|
+
hosted_provider: str | None = None,
|
|
1226
|
+
provider_item_type: str | None = None,
|
|
1227
|
+
provider_item_id: str | None = None,
|
|
1228
|
+
provider_phase: str | None = None,
|
|
1229
|
+
provider_status: str | None = None,
|
|
1230
|
+
retry_safety: str | None = None,
|
|
1231
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1232
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1233
|
+
raw_representation: Any = None,
|
|
1234
|
+
) -> ContentT:
|
|
1235
|
+
"""Create image generation tool result content."""
|
|
1236
|
+
return cls(
|
|
1237
|
+
"image_generation_tool_result",
|
|
1238
|
+
image_id=image_id,
|
|
1239
|
+
outputs=outputs,
|
|
1240
|
+
provider_hosted=True,
|
|
1241
|
+
hosted_family=HostedToolFamily.IMAGE,
|
|
1242
|
+
hosted_provider=hosted_provider,
|
|
1243
|
+
provider_item_type=provider_item_type,
|
|
1244
|
+
provider_item_id=provider_item_id,
|
|
1245
|
+
provider_phase=provider_phase,
|
|
1246
|
+
provider_status=provider_status,
|
|
1247
|
+
retry_safety=retry_safety,
|
|
1248
|
+
annotations=annotations,
|
|
1249
|
+
additional_properties=additional_properties,
|
|
1250
|
+
raw_representation=raw_representation,
|
|
1251
|
+
)
|
|
1252
|
+
|
|
1253
|
+
@classmethod
|
|
1254
|
+
def from_shell_tool_call(
|
|
1255
|
+
cls: type[ContentT],
|
|
1256
|
+
*,
|
|
1257
|
+
call_id: str | None = None,
|
|
1258
|
+
commands: list[str] | None = None,
|
|
1259
|
+
timeout_ms: int | None = None,
|
|
1260
|
+
max_output_length: int | None = None,
|
|
1261
|
+
status: str | None = None,
|
|
1262
|
+
hosted_provider: str | None = None,
|
|
1263
|
+
provider_item_type: str | None = None,
|
|
1264
|
+
provider_item_id: str | None = None,
|
|
1265
|
+
provider_phase: str | None = None,
|
|
1266
|
+
provider_status: str | None = None,
|
|
1267
|
+
retry_safety: str | None = None,
|
|
1268
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1269
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1270
|
+
raw_representation: Any = None,
|
|
1271
|
+
) -> ContentT:
|
|
1272
|
+
"""Create shell tool call content.
|
|
1273
|
+
|
|
1274
|
+
This content represents the model's request to run one or more shell
|
|
1275
|
+
commands. It is request metadata, not command output.
|
|
1276
|
+
|
|
1277
|
+
Keyword Args:
|
|
1278
|
+
call_id: The unique identifier for this tool call.
|
|
1279
|
+
commands: The list of commands to execute.
|
|
1280
|
+
timeout_ms: The timeout in milliseconds for the shell command execution.
|
|
1281
|
+
max_output_length: The maximum output length in characters.
|
|
1282
|
+
status: The status of the shell call (e.g., "in_progress", "completed", "incomplete").
|
|
1283
|
+
annotations: Optional annotations for this content.
|
|
1284
|
+
additional_properties: Optional additional properties.
|
|
1285
|
+
raw_representation: The raw provider-specific representation.
|
|
1286
|
+
"""
|
|
1287
|
+
return cls(
|
|
1288
|
+
"shell_tool_call",
|
|
1289
|
+
call_id=call_id,
|
|
1290
|
+
commands=commands,
|
|
1291
|
+
timeout_ms=timeout_ms,
|
|
1292
|
+
max_output_length=max_output_length,
|
|
1293
|
+
status=status,
|
|
1294
|
+
provider_hosted=True,
|
|
1295
|
+
hosted_family=HostedToolFamily.SHELL,
|
|
1296
|
+
hosted_provider=hosted_provider,
|
|
1297
|
+
provider_item_type=provider_item_type,
|
|
1298
|
+
provider_item_id=provider_item_id,
|
|
1299
|
+
provider_phase=provider_phase,
|
|
1300
|
+
provider_status=provider_status if provider_status is not None else status,
|
|
1301
|
+
retry_safety=retry_safety,
|
|
1302
|
+
annotations=annotations,
|
|
1303
|
+
additional_properties=additional_properties,
|
|
1304
|
+
raw_representation=raw_representation,
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
@classmethod
|
|
1308
|
+
def from_shell_tool_result(
|
|
1309
|
+
cls: type[ContentT],
|
|
1310
|
+
*,
|
|
1311
|
+
call_id: str | None = None,
|
|
1312
|
+
outputs: Sequence[Content] | None = None,
|
|
1313
|
+
max_output_length: int | None = None,
|
|
1314
|
+
hosted_provider: str | None = None,
|
|
1315
|
+
provider_item_type: str | None = None,
|
|
1316
|
+
provider_item_id: str | None = None,
|
|
1317
|
+
provider_phase: str | None = None,
|
|
1318
|
+
provider_status: str | None = None,
|
|
1319
|
+
retry_safety: str | None = None,
|
|
1320
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1321
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1322
|
+
raw_representation: Any = None,
|
|
1323
|
+
) -> ContentT:
|
|
1324
|
+
"""Create shell tool result content.
|
|
1325
|
+
|
|
1326
|
+
This content represents the aggregate result for a shell tool call.
|
|
1327
|
+
Use :meth:`from_shell_command_output` to build each per-command output
|
|
1328
|
+
item and pass those objects via ``outputs``.
|
|
1329
|
+
|
|
1330
|
+
Keyword Args:
|
|
1331
|
+
call_id: The function call ID for which this is the result.
|
|
1332
|
+
outputs: The list of shell command output Content objects.
|
|
1333
|
+
max_output_length: The maximum output length in characters.
|
|
1334
|
+
annotations: Optional annotations for this content.
|
|
1335
|
+
additional_properties: Optional additional properties.
|
|
1336
|
+
raw_representation: The raw provider-specific representation.
|
|
1337
|
+
"""
|
|
1338
|
+
return cls(
|
|
1339
|
+
"shell_tool_result",
|
|
1340
|
+
call_id=call_id,
|
|
1341
|
+
outputs=list(outputs) if outputs is not None else None,
|
|
1342
|
+
max_output_length=max_output_length,
|
|
1343
|
+
provider_hosted=True,
|
|
1344
|
+
hosted_family=HostedToolFamily.SHELL,
|
|
1345
|
+
hosted_provider=hosted_provider,
|
|
1346
|
+
provider_item_type=provider_item_type,
|
|
1347
|
+
provider_item_id=provider_item_id,
|
|
1348
|
+
provider_phase=provider_phase,
|
|
1349
|
+
provider_status=provider_status,
|
|
1350
|
+
retry_safety=retry_safety,
|
|
1351
|
+
annotations=annotations,
|
|
1352
|
+
additional_properties=additional_properties,
|
|
1353
|
+
raw_representation=raw_representation,
|
|
1354
|
+
)
|
|
1355
|
+
|
|
1356
|
+
@classmethod
|
|
1357
|
+
def from_shell_command_output(
|
|
1358
|
+
cls: type[ContentT],
|
|
1359
|
+
*,
|
|
1360
|
+
stdout: str | None = None,
|
|
1361
|
+
stderr: str | None = None,
|
|
1362
|
+
exit_code: int | None = None,
|
|
1363
|
+
timed_out: bool | None = None,
|
|
1364
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1365
|
+
raw_representation: Any = None,
|
|
1366
|
+
) -> ContentT:
|
|
1367
|
+
"""Create shell command output content for one command execution.
|
|
1368
|
+
|
|
1369
|
+
Keyword Args:
|
|
1370
|
+
stdout: The standard output of the command.
|
|
1371
|
+
stderr: The standard error output of the command.
|
|
1372
|
+
exit_code: The exit code of the command, or None if the command timed out.
|
|
1373
|
+
timed_out: Whether the command execution timed out.
|
|
1374
|
+
additional_properties: Optional additional properties.
|
|
1375
|
+
raw_representation: The raw provider-specific representation.
|
|
1376
|
+
"""
|
|
1377
|
+
return cls(
|
|
1378
|
+
"shell_command_output",
|
|
1379
|
+
stdout=stdout,
|
|
1380
|
+
stderr=stderr,
|
|
1381
|
+
exit_code=exit_code,
|
|
1382
|
+
timed_out=timed_out,
|
|
1383
|
+
additional_properties=additional_properties,
|
|
1384
|
+
raw_representation=raw_representation,
|
|
1385
|
+
)
|
|
1386
|
+
|
|
1387
|
+
@classmethod
|
|
1388
|
+
def from_mcp_server_tool_call(
|
|
1389
|
+
cls: type[ContentT],
|
|
1390
|
+
call_id: str,
|
|
1391
|
+
tool_name: str,
|
|
1392
|
+
*,
|
|
1393
|
+
server_name: str | None = None,
|
|
1394
|
+
arguments: str | Mapping[str, Any] | None = None,
|
|
1395
|
+
hosted_provider: str | None = None,
|
|
1396
|
+
provider_item_type: str | None = None,
|
|
1397
|
+
provider_item_id: str | None = None,
|
|
1398
|
+
provider_phase: str | None = None,
|
|
1399
|
+
provider_status: str | None = None,
|
|
1400
|
+
retry_safety: str | None = None,
|
|
1401
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1402
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1403
|
+
raw_representation: Any = None,
|
|
1404
|
+
) -> ContentT:
|
|
1405
|
+
"""Create MCP server tool call content."""
|
|
1406
|
+
return cls(
|
|
1407
|
+
"mcp_server_tool_call",
|
|
1408
|
+
call_id=call_id,
|
|
1409
|
+
tool_name=tool_name,
|
|
1410
|
+
server_name=server_name,
|
|
1411
|
+
arguments=arguments,
|
|
1412
|
+
informational_only=True,
|
|
1413
|
+
provider_hosted=True,
|
|
1414
|
+
hosted_family=HostedToolFamily.MCP,
|
|
1415
|
+
hosted_provider=hosted_provider,
|
|
1416
|
+
provider_item_type=provider_item_type,
|
|
1417
|
+
provider_item_id=provider_item_id,
|
|
1418
|
+
provider_phase=provider_phase,
|
|
1419
|
+
provider_status=provider_status,
|
|
1420
|
+
retry_safety=retry_safety,
|
|
1421
|
+
annotations=annotations,
|
|
1422
|
+
additional_properties=additional_properties,
|
|
1423
|
+
raw_representation=raw_representation,
|
|
1424
|
+
)
|
|
1425
|
+
|
|
1426
|
+
@classmethod
|
|
1427
|
+
def from_mcp_server_tool_result(
|
|
1428
|
+
cls: type[ContentT],
|
|
1429
|
+
call_id: str,
|
|
1430
|
+
*,
|
|
1431
|
+
output: Any = None,
|
|
1432
|
+
hosted_provider: str | None = None,
|
|
1433
|
+
provider_item_type: str | None = None,
|
|
1434
|
+
provider_item_id: str | None = None,
|
|
1435
|
+
provider_phase: str | None = None,
|
|
1436
|
+
provider_status: str | None = None,
|
|
1437
|
+
retry_safety: str | None = None,
|
|
1438
|
+
annotations: Sequence[Annotation] | None = None,
|
|
1439
|
+
additional_properties: MutableMapping[str, Any] | None = None,
|
|
1440
|
+
raw_representation: Any = None,
|
|
1441
|
+
) -> ContentT:
|
|
1442
|
+
"""Create MCP server tool result content."""
|
|
1443
|
+
return cls(
|
|
1444
|
+
"mcp_server_tool_result",
|
|
1445
|
+
call_id=call_id,
|
|
1446
|
+
output=output,
|
|
1447
|
+
provider_hosted=True,
|
|
1448
|
+
hosted_family=HostedToolFamily.MCP,
|
|
1449
|
+
hosted_provider=hosted_provider,
|
|
1450
|
+
provider_item_type=provider_item_type,
|
|
1451
|
+
provider_item_id=provider_item_id,
|
|
1452
|
+
provider_phase=provider_phase,
|
|
1453
|
+
provider_status=provider_status,
|
|
1454
|
+
retry_safety=retry_safety,
|
|
1455
|
+
annotations=annotations,
|
|
1456
|
+
additional_properties=additional_properties,
|
|
1457
|
+
raw_representation=raw_representation,
|
|
1458
|
+
)
|
|
1459
|
+
|
|
1460
|
+
def to_dict(self, *, exclude_none: bool = True, exclude: set[str] | None = None) -> dict[str, Any]:
|
|
1461
|
+
"""Serialize the content to a dictionary."""
|
|
1462
|
+
fields_to_capture = (
|
|
1463
|
+
"text",
|
|
1464
|
+
"protected_data",
|
|
1465
|
+
"uri",
|
|
1466
|
+
"media_type",
|
|
1467
|
+
"message",
|
|
1468
|
+
"error_code",
|
|
1469
|
+
"error_details",
|
|
1470
|
+
"usage_details",
|
|
1471
|
+
"call_id",
|
|
1472
|
+
"name",
|
|
1473
|
+
"arguments",
|
|
1474
|
+
"informational_only",
|
|
1475
|
+
"exception",
|
|
1476
|
+
"result",
|
|
1477
|
+
"items",
|
|
1478
|
+
"file_id",
|
|
1479
|
+
"vector_store_id",
|
|
1480
|
+
"inputs",
|
|
1481
|
+
"outputs",
|
|
1482
|
+
"image_id",
|
|
1483
|
+
"commands",
|
|
1484
|
+
"timeout_ms",
|
|
1485
|
+
"max_output_length",
|
|
1486
|
+
"status",
|
|
1487
|
+
"stdout",
|
|
1488
|
+
"stderr",
|
|
1489
|
+
"exit_code",
|
|
1490
|
+
"timed_out",
|
|
1491
|
+
"tool_name",
|
|
1492
|
+
"server_name",
|
|
1493
|
+
"output",
|
|
1494
|
+
"id",
|
|
1495
|
+
"provider_hosted",
|
|
1496
|
+
"hosted_family",
|
|
1497
|
+
"hosted_provider",
|
|
1498
|
+
"provider_item_type",
|
|
1499
|
+
"provider_item_id",
|
|
1500
|
+
"provider_phase",
|
|
1501
|
+
"provider_status",
|
|
1502
|
+
"retry_safety",
|
|
1503
|
+
"additional_properties",
|
|
1504
|
+
)
|
|
1505
|
+
|
|
1506
|
+
exclude = exclude or set()
|
|
1507
|
+
result: dict[str, Any] = {"type": self.type}
|
|
1508
|
+
|
|
1509
|
+
for field in fields_to_capture:
|
|
1510
|
+
value = getattr(self, field, None)
|
|
1511
|
+
if field in exclude:
|
|
1512
|
+
continue
|
|
1513
|
+
# Keep old/ordinary session payloads byte-shape compatible. Only
|
|
1514
|
+
# informational function calls need this explicit marker; hosted
|
|
1515
|
+
# MCP calls are inherently informational by content type.
|
|
1516
|
+
if field == "informational_only" and (self.type != "function_call" or not value):
|
|
1517
|
+
continue
|
|
1518
|
+
if field == "provider_hosted" and not value:
|
|
1519
|
+
continue
|
|
1520
|
+
if (
|
|
1521
|
+
field
|
|
1522
|
+
in {
|
|
1523
|
+
"hosted_family",
|
|
1524
|
+
"hosted_provider",
|
|
1525
|
+
"provider_item_type",
|
|
1526
|
+
"provider_item_id",
|
|
1527
|
+
"provider_phase",
|
|
1528
|
+
"provider_status",
|
|
1529
|
+
"retry_safety",
|
|
1530
|
+
}
|
|
1531
|
+
and value is None
|
|
1532
|
+
):
|
|
1533
|
+
continue
|
|
1534
|
+
if exclude_none and value is None:
|
|
1535
|
+
continue
|
|
1536
|
+
result[field] = _serialize_value(value, exclude_none)
|
|
1537
|
+
|
|
1538
|
+
if "annotations" not in exclude and self.annotations is not None:
|
|
1539
|
+
result["annotations"] = [
|
|
1540
|
+
{
|
|
1541
|
+
key: _serialize_value(value, exclude_none)
|
|
1542
|
+
for key, value in annotation.items()
|
|
1543
|
+
if key != "raw_representation"
|
|
1544
|
+
}
|
|
1545
|
+
for annotation in self.annotations
|
|
1546
|
+
]
|
|
1547
|
+
|
|
1548
|
+
return result
|
|
1549
|
+
|
|
1550
|
+
def __eq__(self, other: object) -> bool:
|
|
1551
|
+
"""Check if two Content instances are equal by comparing their dict representations."""
|
|
1552
|
+
if not isinstance(other, Content):
|
|
1553
|
+
return False
|
|
1554
|
+
return self.to_dict(exclude_none=False) == other.to_dict(exclude_none=False)
|
|
1555
|
+
|
|
1556
|
+
def __str__(self) -> str:
|
|
1557
|
+
"""Return a string representation of the Content."""
|
|
1558
|
+
if self.type == "error":
|
|
1559
|
+
if self.error_code:
|
|
1560
|
+
return f"Error {self.error_code}: {self.message or ''}"
|
|
1561
|
+
return self.message or "Unknown error"
|
|
1562
|
+
if self.type == "text":
|
|
1563
|
+
return self.text or ""
|
|
1564
|
+
return f"Content(type={self.type})"
|
|
1565
|
+
|
|
1566
|
+
@classmethod
|
|
1567
|
+
def from_dict(cls: type[ContentT], data: Mapping[str, Any]) -> ContentT:
|
|
1568
|
+
"""Create a Content instance from a mapping."""
|
|
1569
|
+
if not (content_type := data.get("type")):
|
|
1570
|
+
raise ValueError("Content mapping requires 'type'")
|
|
1571
|
+
remaining = dict(data)
|
|
1572
|
+
remaining.pop("type", None)
|
|
1573
|
+
annotations = remaining.pop("annotations", None)
|
|
1574
|
+
additional_properties = remaining.pop("additional_properties", None)
|
|
1575
|
+
raw_representation = remaining.pop("raw_representation", None)
|
|
1576
|
+
|
|
1577
|
+
# Special handling for DataContent with data and media_type
|
|
1578
|
+
if content_type == "data" and "data" in remaining and "media_type" in remaining:
|
|
1579
|
+
# Use from_data() to properly create the DataContent with URI
|
|
1580
|
+
return cls.from_data(remaining["data"], remaining["media_type"])
|
|
1581
|
+
|
|
1582
|
+
# Handle list of Content objects (e.g., inputs in code_interpreter_tool_call)
|
|
1583
|
+
if (input_items := remaining.get("inputs")) and isinstance(input_items, list):
|
|
1584
|
+
remaining["inputs"] = [cls.from_dict(item) if isinstance(item, dict) else item for item in input_items] # type: ignore[reportUnknownVariableType]
|
|
1585
|
+
if (output_items := remaining.get("outputs")) and isinstance(output_items, list):
|
|
1586
|
+
remaining["outputs"] = [cls.from_dict(item) if isinstance(item, dict) else item for item in output_items] # type: ignore[reportUnknownVariableType]
|
|
1587
|
+
if (content_items := remaining.get("items")) and isinstance(content_items, list):
|
|
1588
|
+
remaining["items"] = [cls.from_dict(item) if isinstance(item, dict) else item for item in content_items] # type: ignore[reportUnknownVariableType]
|
|
1589
|
+
|
|
1590
|
+
return cls(
|
|
1591
|
+
type=content_type,
|
|
1592
|
+
annotations=annotations,
|
|
1593
|
+
additional_properties=additional_properties,
|
|
1594
|
+
raw_representation=raw_representation,
|
|
1595
|
+
**remaining,
|
|
1596
|
+
)
|
|
1597
|
+
|
|
1598
|
+
def __add__(self, other: Content) -> Content:
|
|
1599
|
+
"""Concatenate or merge two Content instances."""
|
|
1600
|
+
if not isinstance(other, Content):
|
|
1601
|
+
raise TypeError(f"Incompatible type: Cannot add Content with {type(other).__name__}")
|
|
1602
|
+
|
|
1603
|
+
if self.type != other.type:
|
|
1604
|
+
raise TypeError(f"Cannot add Content of type '{self.type}' with type '{other.type}'")
|
|
1605
|
+
|
|
1606
|
+
if self.type == "text":
|
|
1607
|
+
return self._add_text_content(other)
|
|
1608
|
+
if self.type == "text_reasoning":
|
|
1609
|
+
return self._add_text_reasoning_content(other)
|
|
1610
|
+
if self.type == "function_call":
|
|
1611
|
+
return self._add_function_call_content(other)
|
|
1612
|
+
if self.type == "usage":
|
|
1613
|
+
return self._add_usage_content(other)
|
|
1614
|
+
raise ContentError(f"Addition not supported for content type: {self.type}")
|
|
1615
|
+
|
|
1616
|
+
def _add_text_content(self, other: Content) -> Content:
|
|
1617
|
+
"""Add two TextContent instances."""
|
|
1618
|
+
if self.text is None or other.text is None:
|
|
1619
|
+
raise ContentError("Cannot add text content when either text value is None")
|
|
1620
|
+
if self.additional_properties.get(OPENAI_OUTPUT_MESSAGE_ENVELOPE_KEY) != other.additional_properties.get(
|
|
1621
|
+
OPENAI_OUTPUT_MESSAGE_ENVELOPE_KEY
|
|
1622
|
+
):
|
|
1623
|
+
raise AdditionItemMismatch("Cannot merge text contents from different OpenAI Responses output messages")
|
|
1624
|
+
return Content(
|
|
1625
|
+
"text",
|
|
1626
|
+
text=self.text + other.text,
|
|
1627
|
+
annotations=_combine_annotations(self.annotations, other.annotations),
|
|
1628
|
+
additional_properties=_combine_additional_props(self.additional_properties, other.additional_properties),
|
|
1629
|
+
raw_representation=_combine_raw_representations(self.raw_representation, other.raw_representation),
|
|
1630
|
+
)
|
|
1631
|
+
|
|
1632
|
+
def _add_text_reasoning_content(self, other: Content) -> Content:
|
|
1633
|
+
"""Add two TextReasoningContent instances."""
|
|
1634
|
+
# Ensure we do not silently merge contents with conflicting ids
|
|
1635
|
+
if self.id and other.id and self.id != other.id:
|
|
1636
|
+
raise AdditionItemMismatch(
|
|
1637
|
+
f"Cannot add text_reasoning content with different ids: {self.id!r} != {other.id!r}"
|
|
1638
|
+
)
|
|
1639
|
+
combined_id = self.id or other.id
|
|
1640
|
+
|
|
1641
|
+
# Reasoning captured under different wire dialects must never merge:
|
|
1642
|
+
# each side's replay format is provider state, not concatenable text.
|
|
1643
|
+
if self.additional_properties.get("openai_reasoning_format") != other.additional_properties.get(
|
|
1644
|
+
"openai_reasoning_format"
|
|
1645
|
+
):
|
|
1646
|
+
raise AdditionItemMismatch("Cannot merge reasoning contents with different wire formats")
|
|
1647
|
+
if self.additional_properties.get(_ANTHROPIC_REDACTED_THINKING_KEY) != other.additional_properties.get(
|
|
1648
|
+
_ANTHROPIC_REDACTED_THINKING_KEY
|
|
1649
|
+
):
|
|
1650
|
+
raise AdditionItemMismatch("Cannot merge redacted and ordinary Anthropic reasoning contents")
|
|
1651
|
+
# Each side replays only to the endpoint that issued it.
|
|
1652
|
+
if self.additional_properties.get(REASONING_ORIGIN_KEY) != other.additional_properties.get(
|
|
1653
|
+
REASONING_ORIGIN_KEY
|
|
1654
|
+
):
|
|
1655
|
+
raise AdditionItemMismatch("Cannot merge reasoning contents from different endpoints")
|
|
1656
|
+
|
|
1657
|
+
# Concatenate text, handling None values
|
|
1658
|
+
self_text = self.text or "" # type: ignore[attr-defined]
|
|
1659
|
+
other_text = other.text or "" # type: ignore[attr-defined]
|
|
1660
|
+
if (
|
|
1661
|
+
self_text
|
|
1662
|
+
and other_text
|
|
1663
|
+
and ("reasoning_text" in self.additional_properties) != ("reasoning_text" in other.additional_properties)
|
|
1664
|
+
):
|
|
1665
|
+
raise AdditionItemMismatch("Cannot merge reasoning text with a reasoning summary")
|
|
1666
|
+
combined_text = self_text + other_text if (self_text or other_text) else None
|
|
1667
|
+
|
|
1668
|
+
# Handle protected_data replacement. Two id-less sides that BOTH carry
|
|
1669
|
+
# distinct opaque payloads cannot merge by replacement — that silently
|
|
1670
|
+
# drops the earlier payload. Equal non-empty ids keep later-wins: the
|
|
1671
|
+
# ids already matched above, and a same-id pair is the Responses
|
|
1672
|
+
# snapshot→final refinement contract, where the later payload is the
|
|
1673
|
+
# terminal one.
|
|
1674
|
+
if (
|
|
1675
|
+
self.protected_data is not None
|
|
1676
|
+
and other.protected_data is not None
|
|
1677
|
+
and self.protected_data != other.protected_data
|
|
1678
|
+
and not (self.id and other.id)
|
|
1679
|
+
):
|
|
1680
|
+
raise AdditionItemMismatch("Cannot merge reasoning contents that both carry distinct protected payloads")
|
|
1681
|
+
protected_data = other.protected_data if other.protected_data is not None else self.protected_data # type: ignore[attr-defined]
|
|
1682
|
+
|
|
1683
|
+
return Content(
|
|
1684
|
+
"text_reasoning",
|
|
1685
|
+
id=combined_id,
|
|
1686
|
+
text=combined_text,
|
|
1687
|
+
protected_data=protected_data,
|
|
1688
|
+
annotations=_combine_annotations(self.annotations, other.annotations),
|
|
1689
|
+
additional_properties=_combine_additional_props(self.additional_properties, other.additional_properties),
|
|
1690
|
+
raw_representation=_combine_raw_representations(self.raw_representation, other.raw_representation),
|
|
1691
|
+
)
|
|
1692
|
+
|
|
1693
|
+
def _add_function_call_content(self, other: Content) -> Content:
|
|
1694
|
+
"""Add two FunctionCallContent instances."""
|
|
1695
|
+
other_call_id = other.call_id
|
|
1696
|
+
self_call_id = self.call_id
|
|
1697
|
+
if other_call_id and self_call_id != other_call_id:
|
|
1698
|
+
raise ContentError("Cannot add function calls with different call_ids")
|
|
1699
|
+
for key in _RESPONSES_OUTPUT_ITEM_KEYS:
|
|
1700
|
+
mine, theirs = self.additional_properties.get(key), other.additional_properties.get(key)
|
|
1701
|
+
if mine is not None and theirs is not None and mine != theirs:
|
|
1702
|
+
raise AdditionItemMismatch("Cannot merge function calls from different OpenAI Responses output items")
|
|
1703
|
+
|
|
1704
|
+
self_arguments = self.arguments
|
|
1705
|
+
other_arguments = other.arguments
|
|
1706
|
+
|
|
1707
|
+
if not self_arguments:
|
|
1708
|
+
arguments: str | Mapping[str, Any] | None = other_arguments
|
|
1709
|
+
elif not other_arguments:
|
|
1710
|
+
arguments = self_arguments
|
|
1711
|
+
elif isinstance(self_arguments, str) and isinstance(other_arguments, str):
|
|
1712
|
+
arguments = self_arguments + other_arguments
|
|
1713
|
+
elif isinstance(self_arguments, dict) and isinstance(other_arguments, dict):
|
|
1714
|
+
arguments = {**self_arguments, **other_arguments}
|
|
1715
|
+
else:
|
|
1716
|
+
raise TypeError("Incompatible argument types")
|
|
1717
|
+
|
|
1718
|
+
return Content(
|
|
1719
|
+
"function_call",
|
|
1720
|
+
call_id=self_call_id,
|
|
1721
|
+
name=self.name or other.name,
|
|
1722
|
+
arguments=arguments,
|
|
1723
|
+
informational_only=self.informational_only or other.informational_only,
|
|
1724
|
+
exception=self.exception or other.exception,
|
|
1725
|
+
additional_properties=_combine_additional_props(self.additional_properties, other.additional_properties),
|
|
1726
|
+
raw_representation=_combine_raw_representations(self.raw_representation, other.raw_representation),
|
|
1727
|
+
)
|
|
1728
|
+
|
|
1729
|
+
def _add_usage_content(self, other: Content) -> Content:
|
|
1730
|
+
"""Add two UsageContent instances by combining their usage details."""
|
|
1731
|
+
return Content(
|
|
1732
|
+
"usage",
|
|
1733
|
+
usage_details=add_usage_details(self.usage_details, other.usage_details),
|
|
1734
|
+
additional_properties=_combine_additional_props(self.additional_properties, other.additional_properties),
|
|
1735
|
+
raw_representation=_combine_raw_representations(self.raw_representation, other.raw_representation),
|
|
1736
|
+
)
|
|
1737
|
+
|
|
1738
|
+
def has_top_level_media_type(self, top_level_media_type: Literal["application", "audio", "image", "text"]) -> bool:
|
|
1739
|
+
"""Check if content has a specific top-level media type.
|
|
1740
|
+
|
|
1741
|
+
Works with data, uri, and hosted_file content types.
|
|
1742
|
+
|
|
1743
|
+
Args:
|
|
1744
|
+
top_level_media_type: The top-level media type to check for.
|
|
1745
|
+
|
|
1746
|
+
Returns:
|
|
1747
|
+
True if the content's media type matches the specified top-level type.
|
|
1748
|
+
|
|
1749
|
+
Raises:
|
|
1750
|
+
ContentError: If the content type doesn't support media types.
|
|
1751
|
+
|
|
1752
|
+
Examples:
|
|
1753
|
+
.. code-block:: python
|
|
1754
|
+
|
|
1755
|
+
from chrys.kernel._content import Content
|
|
1756
|
+
|
|
1757
|
+
image = Content.from_uri(uri="data:image/png;base64,abc123", media_type="image/png")
|
|
1758
|
+
print(image.has_top_level_media_type("image")) # True
|
|
1759
|
+
print(image.has_top_level_media_type("audio")) # False
|
|
1760
|
+
"""
|
|
1761
|
+
if self.media_type is None:
|
|
1762
|
+
raise ContentError("no media_type found")
|
|
1763
|
+
|
|
1764
|
+
slash_index = self.media_type.find("/")
|
|
1765
|
+
span = self.media_type[:slash_index] if slash_index >= 0 else self.media_type
|
|
1766
|
+
span = span.strip()
|
|
1767
|
+
return span.lower() == top_level_media_type.lower()
|
|
1768
|
+
|
|
1769
|
+
def parse_arguments(self) -> Mapping[str, Any] | None:
|
|
1770
|
+
"""Parse arguments from function_call, mcp_server_tool_call, or search_tool_call content.
|
|
1771
|
+
|
|
1772
|
+
If arguments cannot be parsed as JSON or the result is not a dict,
|
|
1773
|
+
they are returned as a dictionary with a single key "raw".
|
|
1774
|
+
|
|
1775
|
+
Returns:
|
|
1776
|
+
Parsed arguments as a dictionary, or None if no arguments.
|
|
1777
|
+
|
|
1778
|
+
Raises:
|
|
1779
|
+
ContentError: If the content type doesn't support arguments.
|
|
1780
|
+
|
|
1781
|
+
Examples:
|
|
1782
|
+
.. code-block:: python
|
|
1783
|
+
|
|
1784
|
+
from chrys.kernel._content import Content
|
|
1785
|
+
|
|
1786
|
+
func_call = Content.from_function_call(
|
|
1787
|
+
call_id="call_123",
|
|
1788
|
+
name="send_email",
|
|
1789
|
+
arguments='{"to": "user@example.com"}',
|
|
1790
|
+
)
|
|
1791
|
+
args = func_call.parse_arguments()
|
|
1792
|
+
print(args) # {"to": "user@example.com"}
|
|
1793
|
+
"""
|
|
1794
|
+
if self.arguments is None:
|
|
1795
|
+
return None
|
|
1796
|
+
|
|
1797
|
+
if not self.arguments:
|
|
1798
|
+
return {}
|
|
1799
|
+
|
|
1800
|
+
if isinstance(self.arguments, str):
|
|
1801
|
+
# If arguments are a string, try to parse it as JSON
|
|
1802
|
+
try:
|
|
1803
|
+
loaded = json.loads(self.arguments)
|
|
1804
|
+
if isinstance(loaded, dict):
|
|
1805
|
+
return loaded
|
|
1806
|
+
return {"raw": loaded}
|
|
1807
|
+
except json.JSONDecodeError, TypeError:
|
|
1808
|
+
return {"raw": self.arguments}
|
|
1809
|
+
return self.arguments
|
|
1810
|
+
|
|
1811
|
+
|
|
1812
|
+
def _combine_additional_props(
|
|
1813
|
+
self_additional_properties: dict[str, Any], other_additional_properties: dict[str, Any]
|
|
1814
|
+
) -> dict[str, Any]:
|
|
1815
|
+
"""Combine additional properties for addition operations."""
|
|
1816
|
+
combined = {
|
|
1817
|
+
**other_additional_properties,
|
|
1818
|
+
**self_additional_properties,
|
|
1819
|
+
}
|
|
1820
|
+
left_segment_ids = self_additional_properties.get(PRESENTATION_TEXT_SEGMENT_ID_KEY)
|
|
1821
|
+
right_segment_ids = other_additional_properties.get(PRESENTATION_TEXT_SEGMENT_ID_KEY)
|
|
1822
|
+
if left_segment_ids is not None and right_segment_ids is not None:
|
|
1823
|
+
combined[PRESENTATION_TEXT_SEGMENT_ID_KEY] = tuple(
|
|
1824
|
+
dict.fromkeys(
|
|
1825
|
+
segment_id
|
|
1826
|
+
for value in (left_segment_ids, right_segment_ids)
|
|
1827
|
+
for segment_id in (
|
|
1828
|
+
value
|
|
1829
|
+
if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray))
|
|
1830
|
+
else (value,)
|
|
1831
|
+
)
|
|
1832
|
+
if isinstance(segment_id, str) and segment_id
|
|
1833
|
+
)
|
|
1834
|
+
)
|
|
1835
|
+
return combined
|
|
1836
|
+
|
|
1837
|
+
|
|
1838
|
+
def _combine_raw_representations(
|
|
1839
|
+
self_repr: Any,
|
|
1840
|
+
other_repr: Any,
|
|
1841
|
+
) -> Any:
|
|
1842
|
+
"""Combine raw representations for addition operations."""
|
|
1843
|
+
if self_repr is None:
|
|
1844
|
+
return other_repr
|
|
1845
|
+
if other_repr is None:
|
|
1846
|
+
return self_repr
|
|
1847
|
+
self_list = self_repr if isinstance(self_repr, list) else [self_repr] # type: ignore[reportUnknownVariableType]
|
|
1848
|
+
other_list = other_repr if isinstance(other_repr, list) else [other_repr] # type: ignore[reportUnknownVariableType]
|
|
1849
|
+
return self_list + other_list # type: ignore[reportUnknownVariableType]
|
|
1850
|
+
|
|
1851
|
+
|
|
1852
|
+
def _combine_annotations(
|
|
1853
|
+
self_annotations: Sequence[Annotation] | None,
|
|
1854
|
+
other_annotations: Sequence[Annotation] | None,
|
|
1855
|
+
) -> Sequence[Annotation] | None:
|
|
1856
|
+
"""Combine annotations for addition operations."""
|
|
1857
|
+
if self_annotations is None:
|
|
1858
|
+
return other_annotations
|
|
1859
|
+
if other_annotations is None:
|
|
1860
|
+
return self_annotations
|
|
1861
|
+
return [*self_annotations, *other_annotations]
|
|
1862
|
+
|
|
1863
|
+
|
|
1864
|
+
def _text_for_join(content: Content) -> Any:
|
|
1865
|
+
"""Leave validation of the nullable field to ``str.join``, preserving its ``TypeError``."""
|
|
1866
|
+
return content.text
|