alloy-runtime-cli 0.1.0__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.
- alloy_runtime_cli-0.1.0.dist-info/METADATA +61 -0
- alloy_runtime_cli-0.1.0.dist-info/RECORD +451 -0
- alloy_runtime_cli-0.1.0.dist-info/WHEEL +5 -0
- alloy_runtime_cli-0.1.0.dist-info/entry_points.txt +2 -0
- alloy_runtime_cli-0.1.0.dist-info/top_level.txt +1 -0
- cli/__init__.py +0 -0
- cli/commands/__init__.py +0 -0
- cli/commands/admin/__init__.py +0 -0
- cli/commands/admin/bootstrap_command.py +118 -0
- cli/commands/admin/credentials/__init__.py +0 -0
- cli/commands/admin/credentials/create/__init__.py +0 -0
- cli/commands/admin/credentials/create/command.py +148 -0
- cli/commands/admin/credentials/create/presenter.py +16 -0
- cli/commands/admin/credentials/grant/__init__.py +0 -0
- cli/commands/admin/credentials/grant/command.py +119 -0
- cli/commands/admin/credentials/grant/fields.py +33 -0
- cli/commands/admin/credentials/grant/presenter.py +23 -0
- cli/commands/agents/__init__.py +0 -0
- cli/commands/agents/create/__init__.py +0 -0
- cli/commands/agents/create/command.py +475 -0
- cli/commands/agents/create/fields.py +64 -0
- cli/commands/agents/create/presenter.py +68 -0
- cli/commands/agents/delete/__init__.py +0 -0
- cli/commands/agents/delete/command.py +47 -0
- cli/commands/agents/delete/presenter.py +16 -0
- cli/commands/agents/get/command.py +37 -0
- cli/commands/agents/get/presenter.py +32 -0
- cli/commands/agents/list/__init__.py +1 -0
- cli/commands/agents/list/command.py +54 -0
- cli/commands/agents/list/presenter.py +82 -0
- cli/commands/agents/update/__init__.py +0 -0
- cli/commands/agents/update/command.py +435 -0
- cli/commands/agents/update/fields.py +40 -0
- cli/commands/agents/update/presenter.py +68 -0
- cli/commands/audio/__init__.py +0 -0
- cli/commands/audio/transcribe/__init__.py +0 -0
- cli/commands/audio/transcribe/command.py +144 -0
- cli/commands/audio/transcribe/presenter.py +15 -0
- cli/commands/auth/__init__.py +0 -0
- cli/commands/auth/login/__init__.py +0 -0
- cli/commands/auth/login/command.py +80 -0
- cli/commands/auth/signup/__init__.py +0 -0
- cli/commands/auth/signup/command.py +115 -0
- cli/commands/billing/__init__.py +1 -0
- cli/commands/billing/costs/__init__.py +1 -0
- cli/commands/billing/costs/by_agent/__init__.py +1 -0
- cli/commands/billing/costs/by_agent/command.py +57 -0
- cli/commands/billing/costs/by_agent/presenter.py +81 -0
- cli/commands/billing/costs/by_model/__init__.py +1 -0
- cli/commands/billing/costs/by_model/command.py +57 -0
- cli/commands/billing/costs/by_model/presenter.py +80 -0
- cli/commands/billing/costs/daily/__init__.py +1 -0
- cli/commands/billing/costs/daily/command.py +55 -0
- cli/commands/billing/costs/daily/presenter.py +75 -0
- cli/commands/billing/costs/summary/__init__.py +1 -0
- cli/commands/billing/costs/summary/command.py +57 -0
- cli/commands/billing/costs/summary/presenter.py +42 -0
- cli/commands/billing/projects/__init__.py +1 -0
- cli/commands/billing/projects/create/__init__.py +1 -0
- cli/commands/billing/projects/create/command.py +60 -0
- cli/commands/billing/projects/create/presenter.py +26 -0
- cli/commands/billing/projects/get/__init__.py +1 -0
- cli/commands/billing/projects/get/command.py +33 -0
- cli/commands/billing/projects/get/presenter.py +32 -0
- cli/commands/billing/projects/list/__init__.py +1 -0
- cli/commands/billing/projects/list/command.py +40 -0
- cli/commands/billing/projects/list/presenter.py +57 -0
- cli/commands/content/__init__.py +1 -0
- cli/commands/content/delete/__init__.py +0 -0
- cli/commands/content/delete/command.py +49 -0
- cli/commands/content/delete/presenter.py +18 -0
- cli/commands/content/edit/__init__.py +1 -0
- cli/commands/content/edit/command.py +155 -0
- cli/commands/content/edit/editor.py +150 -0
- cli/commands/content/edit/presenter.py +146 -0
- cli/commands/content/get/__init__.py +1 -0
- cli/commands/content/get/command.py +39 -0
- cli/commands/content/get/presenter.py +176 -0
- cli/commands/content/list/__init__.py +1 -0
- cli/commands/content/list/command.py +347 -0
- cli/commands/content/list/export_formatters.py +409 -0
- cli/commands/content/list/export_handler.py +165 -0
- cli/commands/content/list/presenter.py +190 -0
- cli/commands/credentials/__init__.py +0 -0
- cli/commands/credentials/create/__init__.py +0 -0
- cli/commands/credentials/create/command.py +165 -0
- cli/commands/credentials/create/fields.py +38 -0
- cli/commands/credentials/create/presenter.py +20 -0
- cli/commands/credentials/update/__init__.py +0 -0
- cli/commands/credentials/update/command.py +53 -0
- cli/commands/credentials/update/fields.py +71 -0
- cli/commands/credentials/update/presenter.py +16 -0
- cli/commands/flag_utils.py +366 -0
- cli/commands/generate/__init__.py +0 -0
- cli/commands/generate/cancel/__init__.py +1 -0
- cli/commands/generate/cancel/command.py +44 -0
- cli/commands/generate/cancel/presenter.py +26 -0
- cli/commands/generate/status/__init__.py +1 -0
- cli/commands/generate/status/command.py +58 -0
- cli/commands/generate/status/presenter.py +78 -0
- cli/commands/generate/text/__init__.py +0 -0
- cli/commands/generate/text/command.py +1325 -0
- cli/commands/generate/text/concurrent_renderer.py +355 -0
- cli/commands/generate/text/presenter.py +287 -0
- cli/commands/generate/text/stream_renderer.py +129 -0
- cli/commands/knowledge/__init__.py +0 -0
- cli/commands/knowledge/collections/__init__.py +0 -0
- cli/commands/knowledge/collections/cluster/__init__.py +0 -0
- cli/commands/knowledge/collections/cluster/command.py +64 -0
- cli/commands/knowledge/collections/cluster/presenter.py +74 -0
- cli/commands/knowledge/collections/cluster_status/__init__.py +0 -0
- cli/commands/knowledge/collections/cluster_status/command.py +46 -0
- cli/commands/knowledge/collections/cluster_status/presenter.py +10 -0
- cli/commands/knowledge/collections/create/__init__.py +0 -0
- cli/commands/knowledge/collections/create/command.py +137 -0
- cli/commands/knowledge/collections/create/presenter.py +38 -0
- cli/commands/knowledge/collections/delete/__init__.py +1 -0
- cli/commands/knowledge/collections/delete/command.py +47 -0
- cli/commands/knowledge/collections/delete/presenter.py +20 -0
- cli/commands/knowledge/collections/get/__init__.py +1 -0
- cli/commands/knowledge/collections/get/command.py +30 -0
- cli/commands/knowledge/collections/get/presenter.py +44 -0
- cli/commands/knowledge/collections/list/__init__.py +1 -0
- cli/commands/knowledge/collections/list/command.py +41 -0
- cli/commands/knowledge/collections/list/presenter.py +68 -0
- cli/commands/knowledge/collections/update/__init__.py +0 -0
- cli/commands/knowledge/collections/update/command.py +97 -0
- cli/commands/knowledge/collections/update/presenter.py +42 -0
- cli/commands/knowledge/documents/__init__.py +0 -0
- cli/commands/knowledge/documents/bulk_metadata/__init__.py +0 -0
- cli/commands/knowledge/documents/bulk_metadata/command.py +119 -0
- cli/commands/knowledge/documents/bulk_metadata/presenter.py +36 -0
- cli/commands/knowledge/documents/delete/__init__.py +0 -0
- cli/commands/knowledge/documents/delete/command.py +47 -0
- cli/commands/knowledge/documents/delete/presenter.py +20 -0
- cli/commands/knowledge/documents/get/__init__.py +0 -0
- cli/commands/knowledge/documents/get/command.py +39 -0
- cli/commands/knowledge/documents/get/presenter.py +78 -0
- cli/commands/knowledge/documents/ingest/__init__.py +0 -0
- cli/commands/knowledge/documents/ingest/command.py +222 -0
- cli/commands/knowledge/documents/ingest/presenter.py +41 -0
- cli/commands/knowledge/documents/list/__init__.py +0 -0
- cli/commands/knowledge/documents/list/command.py +69 -0
- cli/commands/knowledge/documents/list/presenter.py +86 -0
- cli/commands/knowledge/documents/reingest/__init__.py +0 -0
- cli/commands/knowledge/documents/reingest/command.py +102 -0
- cli/commands/knowledge/documents/reingest/presenter.py +70 -0
- cli/commands/knowledge/documents/update/__init__.py +0 -0
- cli/commands/knowledge/documents/update/command.py +85 -0
- cli/commands/knowledge/documents/update/presenter.py +37 -0
- cli/commands/knowledge/recover/__init__.py +0 -0
- cli/commands/knowledge/recover/command.py +46 -0
- cli/commands/knowledge/recover/presenter.py +79 -0
- cli/commands/knowledge/search/__init__.py +0 -0
- cli/commands/knowledge/search/command.py +218 -0
- cli/commands/knowledge/search/presenter.py +111 -0
- cli/commands/knowledge/synthesis/__init__.py +0 -0
- cli/commands/knowledge/synthesis/create/__init__.py +0 -0
- cli/commands/knowledge/synthesis/create/command.py +127 -0
- cli/commands/knowledge/synthesis/create/presenter.py +33 -0
- cli/commands/knowledge/synthesis/delete/__init__.py +0 -0
- cli/commands/knowledge/synthesis/delete/command.py +53 -0
- cli/commands/knowledge/synthesis/delete/presenter.py +31 -0
- cli/commands/knowledge/synthesis/get/__init__.py +0 -0
- cli/commands/knowledge/synthesis/get/command.py +55 -0
- cli/commands/knowledge/synthesis/get/presenter.py +114 -0
- cli/commands/knowledge/synthesis/list/__init__.py +0 -0
- cli/commands/knowledge/synthesis/list/command.py +132 -0
- cli/commands/knowledge/synthesis/list/presenter.py +84 -0
- cli/commands/knowledge/synthesis/refresh/__init__.py +0 -0
- cli/commands/knowledge/synthesis/refresh/command.py +42 -0
- cli/commands/knowledge/synthesis/refresh/presenter.py +33 -0
- cli/commands/knowledge/synthesis/update/__init__.py +0 -0
- cli/commands/knowledge/synthesis/update/command.py +76 -0
- cli/commands/knowledge/synthesis/update/presenter.py +41 -0
- cli/commands/models/__init__.py +0 -0
- cli/commands/models/list/__init__.py +0 -0
- cli/commands/models/list/command.py +84 -0
- cli/commands/models/list/presenter.py +114 -0
- cli/commands/organizations/__init__.py +0 -0
- cli/commands/organizations/create/command.py +32 -0
- cli/commands/organizations/create/presenter.py +9 -0
- cli/commands/pipelines/__init__.py +1 -0
- cli/commands/pipelines/approvals/__init__.py +1 -0
- cli/commands/pipelines/approvals/decide_command.py +77 -0
- cli/commands/pipelines/approvals/get_command.py +44 -0
- cli/commands/pipelines/approvals/presenter.py +56 -0
- cli/commands/pipelines/costs/__init__.py +1 -0
- cli/commands/pipelines/costs/command.py +57 -0
- cli/commands/pipelines/costs/daily_command.py +54 -0
- cli/commands/pipelines/costs/daily_presenter.py +59 -0
- cli/commands/pipelines/costs/presenter.py +37 -0
- cli/commands/pipelines/create/__init__.py +1 -0
- cli/commands/pipelines/create/command.py +103 -0
- cli/commands/pipelines/create/presenter.py +22 -0
- cli/commands/pipelines/env_vars/__init__.py +1 -0
- cli/commands/pipelines/env_vars/command.py +51 -0
- cli/commands/pipelines/env_vars/presenter.py +16 -0
- cli/commands/pipelines/execute/__init__.py +1 -0
- cli/commands/pipelines/execute/command.py +142 -0
- cli/commands/pipelines/execute/presenter.py +47 -0
- cli/commands/pipelines/executions/__init__.py +1 -0
- cli/commands/pipelines/executions/costs/__init__.py +1 -0
- cli/commands/pipelines/executions/costs/command.py +48 -0
- cli/commands/pipelines/executions/costs/presenter.py +29 -0
- cli/commands/pipelines/executions/costs_by_model/__init__.py +1 -0
- cli/commands/pipelines/executions/costs_by_model/command.py +50 -0
- cli/commands/pipelines/executions/costs_by_model/presenter.py +78 -0
- cli/commands/pipelines/executions/costs_by_step/__init__.py +1 -0
- cli/commands/pipelines/executions/costs_by_step/command.py +50 -0
- cli/commands/pipelines/executions/costs_by_step/presenter.py +72 -0
- cli/commands/pipelines/executions/get_command.py +38 -0
- cli/commands/pipelines/executions/list_command.py +123 -0
- cli/commands/pipelines/executions/presenter.py +131 -0
- cli/commands/pipelines/executions/rerun_command.py +41 -0
- cli/commands/pipelines/executions/update/__init__.py +1 -0
- cli/commands/pipelines/executions/update/command.py +110 -0
- cli/commands/pipelines/executions/update/presenter.py +28 -0
- cli/commands/pipelines/get/__init__.py +1 -0
- cli/commands/pipelines/get/command.py +33 -0
- cli/commands/pipelines/get/presenter.py +48 -0
- cli/commands/pipelines/list/__init__.py +1 -0
- cli/commands/pipelines/list/command.py +53 -0
- cli/commands/pipelines/list/presenter.py +66 -0
- cli/commands/pipelines/schedules/__init__.py +1 -0
- cli/commands/pipelines/schedules/create_command.py +119 -0
- cli/commands/pipelines/schedules/create_presenter.py +35 -0
- cli/commands/pipelines/schedules/delete_command.py +52 -0
- cli/commands/pipelines/schedules/env_vars_command.py +59 -0
- cli/commands/pipelines/schedules/env_vars_presenter.py +16 -0
- cli/commands/pipelines/schedules/get_command.py +38 -0
- cli/commands/pipelines/schedules/list_command.py +33 -0
- cli/commands/pipelines/schedules/once_command.py +90 -0
- cli/commands/pipelines/schedules/once_presenter.py +30 -0
- cli/commands/pipelines/schedules/presenter.py +104 -0
- cli/commands/pipelines/schedules/update_command.py +139 -0
- cli/commands/pipelines/schedules/update_presenter.py +29 -0
- cli/commands/render/__init__.py +0 -0
- cli/commands/render/html_to_image/__init__.py +0 -0
- cli/commands/render/html_to_image/command.py +170 -0
- cli/commands/schemas/__init__.py +0 -0
- cli/commands/schemas/create/__init__.py +0 -0
- cli/commands/schemas/create/command.py +122 -0
- cli/commands/schemas/create/presenter.py +53 -0
- cli/commands/schemas/delete/command.py +45 -0
- cli/commands/schemas/delete/presenter.py +9 -0
- cli/commands/schemas/get/__init__.py +0 -0
- cli/commands/schemas/get/command.py +56 -0
- cli/commands/schemas/get/presenter.py +129 -0
- cli/commands/schemas/list/__init__.py +0 -0
- cli/commands/schemas/list/command.py +64 -0
- cli/commands/schemas/list/presenter.py +133 -0
- cli/commands/schemas/update/__init__.py +0 -0
- cli/commands/schemas/update/command.py +369 -0
- cli/commands/schemas/update/presenter.py +53 -0
- cli/commands/sessions/__init__.py +1 -0
- cli/commands/sessions/delete/__init__.py +1 -0
- cli/commands/sessions/delete/command.py +47 -0
- cli/commands/sessions/delete/presenter.py +10 -0
- cli/commands/sessions/get/__init__.py +1 -0
- cli/commands/sessions/get/command.py +42 -0
- cli/commands/sessions/get/presenter.py +59 -0
- cli/commands/sessions/list/__init__.py +1 -0
- cli/commands/sessions/list/command.py +61 -0
- cli/commands/sessions/list/presenter.py +68 -0
- cli/commands/sessions/messages/__init__.py +1 -0
- cli/commands/sessions/messages/command.py +78 -0
- cli/commands/sessions/messages/presenter.py +79 -0
- cli/commands/shared_flags.py +500 -0
- cli/commands/sync/__init__.py +0 -0
- cli/commands/sync/command.py +45 -0
- cli/commands/sync/presenter.py +49 -0
- cli/commands/tags/__init__.py +1 -0
- cli/commands/tags/create/__init__.py +1 -0
- cli/commands/tags/create/command.py +60 -0
- cli/commands/tags/delete/__init__.py +1 -0
- cli/commands/tags/delete/command.py +47 -0
- cli/commands/tags/delete/presenter.py +10 -0
- cli/commands/tags/get/command.py +31 -0
- cli/commands/tags/get/presenter.py +23 -0
- cli/commands/tags/list/__init__.py +1 -0
- cli/commands/tags/list/command.py +52 -0
- cli/commands/tags/list/presenter.py +49 -0
- cli/commands/tags/update/command.py +64 -0
- cli/commands/tags/update/presenter.py +9 -0
- cli/commands/templates/__init__.py +0 -0
- cli/commands/templates/create/__init__.py +0 -0
- cli/commands/templates/create/command.py +152 -0
- cli/commands/templates/create/presenter.py +86 -0
- cli/commands/templates/delete/__init__.py +0 -0
- cli/commands/templates/delete/command.py +47 -0
- cli/commands/templates/delete/presenter.py +16 -0
- cli/commands/templates/get/__init__.py +0 -0
- cli/commands/templates/get/command.py +52 -0
- cli/commands/templates/get/presenter.py +233 -0
- cli/commands/templates/get_by_version/command.py +32 -0
- cli/commands/templates/get_by_version/presenter.py +30 -0
- cli/commands/templates/list/__init__.py +1 -0
- cli/commands/templates/list/command.py +102 -0
- cli/commands/templates/list/presenter.py +93 -0
- cli/commands/templates/render/__init__.py +0 -0
- cli/commands/templates/render/command.py +115 -0
- cli/commands/templates/render/presenter.py +276 -0
- cli/commands/templates/update/__init__.py +0 -0
- cli/commands/templates/update/command.py +199 -0
- cli/commands/templates/update/presenter.py +94 -0
- cli/commands/templates/version/__init__.py +1 -0
- cli/commands/templates/version/command.py +116 -0
- cli/commands/templates/version/presenter.py +100 -0
- cli/commands/tool_configs/__init__.py +0 -0
- cli/commands/tool_configs/create/__init__.py +0 -0
- cli/commands/tool_configs/create/command.py +118 -0
- cli/commands/tool_configs/create/presenter.py +53 -0
- cli/commands/tool_configs/delete/__init__.py +0 -0
- cli/commands/tool_configs/delete/command.py +47 -0
- cli/commands/tool_configs/delete/presenter.py +18 -0
- cli/commands/tool_configs/get/__init__.py +0 -0
- cli/commands/tool_configs/get/command.py +31 -0
- cli/commands/tool_configs/get/presenter.py +62 -0
- cli/commands/tool_configs/list/__init__.py +0 -0
- cli/commands/tool_configs/list/command.py +59 -0
- cli/commands/tool_configs/list/presenter.py +60 -0
- cli/commands/tool_configs/update/__init__.py +0 -0
- cli/commands/tool_configs/update/command.py +128 -0
- cli/commands/tool_configs/update/presenter.py +53 -0
- cli/commands/tools/__init__.py +1 -0
- cli/commands/tools/get/__init__.py +1 -0
- cli/commands/tools/get/command.py +42 -0
- cli/commands/tools/get/presenter.py +45 -0
- cli/commands/tools/list/__init__.py +1 -0
- cli/commands/tools/list/command.py +56 -0
- cli/commands/tools/list/presenter.py +44 -0
- cli/commands/users/__init__.py +0 -0
- cli/commands/users/create/command.py +53 -0
- cli/commands/users/create/presenter.py +9 -0
- cli/commands/whoami/__init__.py +0 -0
- cli/commands/whoami/command.py +42 -0
- cli/infrastructure/__init__.py +0 -0
- cli/infrastructure/auth_storage.py +71 -0
- cli/infrastructure/client_factory.py +36 -0
- cli/infrastructure/command.py +75 -0
- cli/infrastructure/config.py +188 -0
- cli/infrastructure/console.py +27 -0
- cli/infrastructure/editor.py +138 -0
- cli/infrastructure/error_display.py +178 -0
- cli/infrastructure/field_extractor.py +360 -0
- cli/infrastructure/file_content.py +210 -0
- cli/infrastructure/filter_parser.py +256 -0
- cli/infrastructure/formatters/__init__.py +0 -0
- cli/infrastructure/formatters/base.py +99 -0
- cli/infrastructure/formatters/compact_formatter.py +245 -0
- cli/infrastructure/formatters/json_formatter.py +84 -0
- cli/infrastructure/formatters/lines_formatter.py +102 -0
- cli/infrastructure/formatting/__init__.py +0 -0
- cli/infrastructure/formatting/fields.py +193 -0
- cli/infrastructure/forms/__init__.py +0 -0
- cli/infrastructure/forms/agent_picker.py +123 -0
- cli/infrastructure/forms/agent_tool_editor.py +384 -0
- cli/infrastructure/forms/agent_tools_manager.py +212 -0
- cli/infrastructure/forms/base_picker.py +469 -0
- cli/infrastructure/forms/components.py +126 -0
- cli/infrastructure/forms/json_schema_builder.py +149 -0
- cli/infrastructure/forms/model_picker.py +134 -0
- cli/infrastructure/forms/parsers.py +173 -0
- cli/infrastructure/forms/resolution_modal.py +302 -0
- cli/infrastructure/forms/schema_picker.py +137 -0
- cli/infrastructure/forms/tag_management_modal.py +103 -0
- cli/infrastructure/forms/tag_picker.py +207 -0
- cli/infrastructure/forms/template_picker.py +131 -0
- cli/infrastructure/forms/tool_config_picker.py +130 -0
- cli/infrastructure/forms/tool_picker.py +103 -0
- cli/infrastructure/injection/__init__.py +0 -0
- cli/infrastructure/injection/parser.py +302 -0
- cli/infrastructure/injection/resolver.py +399 -0
- cli/infrastructure/kv_parser.py +130 -0
- cli/infrastructure/local_storage.py +227 -0
- cli/infrastructure/macro_parser.py +215 -0
- cli/infrastructure/output.py +192 -0
- cli/infrastructure/provider_setup.py +81 -0
- cli/infrastructure/renderers/__init__.py +0 -0
- cli/infrastructure/renderers/entity_renderer.py +77 -0
- cli/infrastructure/renderers/list_renderer.py +114 -0
- cli/infrastructure/scope_utils.py +47 -0
- cli/infrastructure/spinner.py +101 -0
- cli/infrastructure/tui/__init__.py +0 -0
- cli/infrastructure/tui/clipboard.py +41 -0
- cli/infrastructure/tui/formatters.py +105 -0
- cli/infrastructure/tui/preview.py +14 -0
- cli/infrastructure/tui/selectable.py +198 -0
- cli/infrastructure/validation/__init__.py +0 -0
- cli/infrastructure/validation/tag_validation.py +74 -0
- cli/main.py +759 -0
- cli/tui/__init__.py +0 -0
- cli/tui/app.py +199 -0
- cli/tui/app_store.py +73 -0
- cli/tui/chat/__init__.py +0 -0
- cli/tui/chat/commands/__init__.py +0 -0
- cli/tui/chat/commands/base.py +65 -0
- cli/tui/chat/commands/create_session.py +135 -0
- cli/tui/chat/commands/load_session.py +119 -0
- cli/tui/chat/commands/regenerate.py +120 -0
- cli/tui/chat/commands/reload_session.py +63 -0
- cli/tui/chat/commands/send_message.py +190 -0
- cli/tui/chat/commands/undo.py +66 -0
- cli/tui/chat/editor.py +71 -0
- cli/tui/chat/messages.py +223 -0
- cli/tui/chat/pane.py +141 -0
- cli/tui/chat/renderers/__init__.py +0 -0
- cli/tui/chat/renderers/base.py +72 -0
- cli/tui/chat/renderers/markdown.py +250 -0
- cli/tui/chat/renderers/plain.py +83 -0
- cli/tui/chat/screen.py +1155 -0
- cli/tui/chat/services/__init__.py +0 -0
- cli/tui/chat/services/injection.py +386 -0
- cli/tui/chat/services/name_generator.py +256 -0
- cli/tui/chat/slash_commands.py +424 -0
- cli/tui/chat/store.py +280 -0
- cli/tui/chat/types.py +220 -0
- cli/tui/chat/widgets/__init__.py +0 -0
- cli/tui/chat/widgets/chat_header.py +75 -0
- cli/tui/chat/widgets/chat_input.py +362 -0
- cli/tui/chat/widgets/injection_popup.py +161 -0
- cli/tui/chat/widgets/message_display.py +287 -0
- cli/tui/chat/widgets/session_sidebar.py +214 -0
- cli/tui/chat/widgets/welcome_screen.py +290 -0
- cli/tui/screens/__init__.py +0 -0
- cli/tui/screens/agents.py +344 -0
- cli/tui/screens/base.py +301 -0
- cli/tui/screens/content.py +508 -0
- cli/tui/screens/dashboard.py +89 -0
- cli/tui/screens/models.py +96 -0
- cli/tui/screens/nav_screen.py +186 -0
- cli/tui/screens/schemas.py +522 -0
- cli/tui/screens/templates.py +734 -0
- cli/tui/screens/tool_configs.py +335 -0
- cli/tui/styles/__init__.py +0 -0
- cli/tui/widgets/__init__.py +0 -0
- cli/tui/widgets/agent_create_modal.py +139 -0
- cli/tui/widgets/agent_form_modal.py +659 -0
- cli/tui/widgets/agent_update_modal.py +299 -0
- cli/tui/widgets/base_form_modal.py +77 -0
- cli/tui/widgets/confirm_modal.py +75 -0
- cli/tui/widgets/help_modal.py +145 -0
- cli/tui/widgets/new_session_modal.py +328 -0
- cli/tui/widgets/schema_create_modal.py +271 -0
- cli/tui/widgets/schema_update_modal.py +188 -0
- cli/tui/widgets/status_footer.py +147 -0
- cli/tui/widgets/template_create_modal.py +502 -0
- cli/tui/widgets/template_update_modal.py +308 -0
- cli/tui/widgets/tool_config_create_modal.py +216 -0
- cli/tui/widgets/tool_config_update_modal.py +208 -0
cli/tui/__init__.py
ADDED
|
File without changes
|
cli/tui/app.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Unified Alloy Runtime Terminal Application.
|
|
2
|
+
|
|
3
|
+
This module provides the main Textual application that serves as the unified TUI
|
|
4
|
+
for Alloy Runtime. It uses a screen-based architecture where each main view
|
|
5
|
+
(Chat, Agents, Templates, Content, Schemas) is a proper Textual Screen.
|
|
6
|
+
|
|
7
|
+
The app uses:
|
|
8
|
+
- Screen stack for navigation between main views
|
|
9
|
+
- AppStore for shared state following Textual's "App as Store" pattern
|
|
10
|
+
- Priority bindings for global navigation that work regardless of focus
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Literal
|
|
14
|
+
|
|
15
|
+
from textual.app import App
|
|
16
|
+
|
|
17
|
+
from cli.tui.app_store import AppStore
|
|
18
|
+
from cli.tui.chat.screen import ChatScreen
|
|
19
|
+
from cli.tui.screens.agents import AgentsScreen
|
|
20
|
+
from cli.tui.screens.content import ContentScreen
|
|
21
|
+
from cli.tui.screens.dashboard import DashboardScreen
|
|
22
|
+
from cli.tui.screens.schemas import SchemasScreen
|
|
23
|
+
from cli.tui.screens.templates import TemplatesScreen
|
|
24
|
+
from cli.tui.screens.tool_configs import ToolConfigsScreen
|
|
25
|
+
from cli.tui.widgets.status_footer import StatusFooter
|
|
26
|
+
from alloy_runtime_sdk.logging.config import get_logger
|
|
27
|
+
|
|
28
|
+
logger = get_logger(__name__)
|
|
29
|
+
|
|
30
|
+
SeverityLevel = Literal["information", "warning", "error"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AlloyRuntimeApp(App[None]):
|
|
34
|
+
"""Unified Alloy Runtime Terminal Application.
|
|
35
|
+
|
|
36
|
+
A full-featured TUI that provides:
|
|
37
|
+
- Screen-based navigation between major sections
|
|
38
|
+
- Consistent keyboard shortcuts across all views (c/a/t/s/m for switching)
|
|
39
|
+
- Integrated chat, browse, and create workflows
|
|
40
|
+
- Simple shared store accessible via self.app.store
|
|
41
|
+
|
|
42
|
+
Navigation:
|
|
43
|
+
- c: Chat screen
|
|
44
|
+
- a: Agents screen
|
|
45
|
+
- t: Templates screen
|
|
46
|
+
- m: Content (media) screen
|
|
47
|
+
- s: Schemas screen
|
|
48
|
+
- d: Dashboard overlay
|
|
49
|
+
- ?: Help modal
|
|
50
|
+
|
|
51
|
+
All screens inherit from NavScreen which provides these navigation bindings
|
|
52
|
+
as priority bindings, ensuring they work regardless of focus state.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
CSS_PATH = [
|
|
56
|
+
"styles/app.tcss",
|
|
57
|
+
"styles/browser.tcss",
|
|
58
|
+
"styles/chat.tcss",
|
|
59
|
+
"styles/modals.tcss",
|
|
60
|
+
"styles/forms.tcss",
|
|
61
|
+
"styles/dashboard.tcss",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
# No bindings at app level - all bindings are on screens
|
|
65
|
+
# This avoids conflicts and ensures proper screen isolation
|
|
66
|
+
BINDINGS = []
|
|
67
|
+
|
|
68
|
+
# Register screens with the app
|
|
69
|
+
SCREENS = {
|
|
70
|
+
"chat": ChatScreen,
|
|
71
|
+
"agents": AgentsScreen,
|
|
72
|
+
"templates": TemplatesScreen,
|
|
73
|
+
"content": ContentScreen,
|
|
74
|
+
"schemas": SchemasScreen,
|
|
75
|
+
"tool_configs": ToolConfigsScreen,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
theme: str = "tokyo-night" # type: ignore[assignment]
|
|
79
|
+
|
|
80
|
+
def __init__(self, api_url: str, api_key: str):
|
|
81
|
+
"""Initialize the Alloy Runtime app.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
api_url: Base API URL for the server
|
|
85
|
+
api_key: API key for authentication
|
|
86
|
+
"""
|
|
87
|
+
super().__init__()
|
|
88
|
+
# Create the simple store - screens access via self.app.store
|
|
89
|
+
self.store = AppStore(api_url=api_url, api_key=api_key)
|
|
90
|
+
# Track current screen for navigation
|
|
91
|
+
self._current_screen_id: str = "chat"
|
|
92
|
+
logger.info("tui_app_initialized", api_url=api_url)
|
|
93
|
+
|
|
94
|
+
def on_mount(self) -> None:
|
|
95
|
+
"""Set up initial state on startup."""
|
|
96
|
+
logger.info("tui_app_mounted")
|
|
97
|
+
# Push the dashboard screen first, then the chat screen
|
|
98
|
+
# Dashboard will be shown as an overlay
|
|
99
|
+
self.push_screen("chat")
|
|
100
|
+
self.push_screen(DashboardScreen(), self._on_dashboard_dismiss)
|
|
101
|
+
|
|
102
|
+
def _on_dashboard_dismiss(self, screen_id: str | None) -> None:
|
|
103
|
+
"""Handle dashboard dismissal by switching to the selected screen.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
screen_id: The screen ID to navigate to (e.g., "chat", "agents"), or None if dismissed without selection
|
|
107
|
+
"""
|
|
108
|
+
if screen_id is None:
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
# Extract just the screen name from tab-* format if needed
|
|
112
|
+
if screen_id.startswith("tab-"):
|
|
113
|
+
screen_id = screen_id[4:] # Remove "tab-" prefix
|
|
114
|
+
|
|
115
|
+
logger.info("dashboard_dismissed", target_screen=screen_id)
|
|
116
|
+
self.switch_to_screen(screen_id)
|
|
117
|
+
|
|
118
|
+
def switch_to_screen(self, screen_id: str) -> None:
|
|
119
|
+
"""Switch to a different screen.
|
|
120
|
+
|
|
121
|
+
This method handles screen switching by:
|
|
122
|
+
1. Popping the current screen
|
|
123
|
+
2. Pushing the new screen
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
screen_id: The ID of the screen to switch to (chat, agents, templates, content, schemas)
|
|
127
|
+
"""
|
|
128
|
+
if screen_id == self._current_screen_id:
|
|
129
|
+
return # Already on this screen
|
|
130
|
+
|
|
131
|
+
if screen_id not in self.SCREENS:
|
|
132
|
+
logger.warning("unknown_screen_id", screen_id=screen_id)
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
logger.info(
|
|
136
|
+
"switching_screen", from_screen=self._current_screen_id, to_screen=screen_id
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Use switch_screen for clean transitions
|
|
140
|
+
self._current_screen_id = screen_id
|
|
141
|
+
self.switch_screen(screen_id) # pyright: ignore[reportUnknownMemberType]
|
|
142
|
+
|
|
143
|
+
def notify(
|
|
144
|
+
self,
|
|
145
|
+
message: str,
|
|
146
|
+
*,
|
|
147
|
+
title: str = "",
|
|
148
|
+
severity: SeverityLevel = "information",
|
|
149
|
+
timeout: float | None = None,
|
|
150
|
+
markup: bool = True,
|
|
151
|
+
) -> None:
|
|
152
|
+
"""Show a notification in the status footer instead of a toast.
|
|
153
|
+
|
|
154
|
+
This overrides the default App.notify() to route notifications
|
|
155
|
+
to our vim-style StatusFooter widget if available.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
message: The notification message
|
|
159
|
+
title: Optional title (ignored for status bar)
|
|
160
|
+
severity: One of "information", "warning", "error"
|
|
161
|
+
timeout: Seconds before clearing (default varies by severity)
|
|
162
|
+
markup: Whether message contains markup (ignored for status bar)
|
|
163
|
+
"""
|
|
164
|
+
# Errors get longer display time (6s) so users can read them
|
|
165
|
+
if timeout is not None:
|
|
166
|
+
effective_timeout = timeout
|
|
167
|
+
elif severity == "error":
|
|
168
|
+
effective_timeout = 6.0
|
|
169
|
+
else:
|
|
170
|
+
effective_timeout = 2.0
|
|
171
|
+
try:
|
|
172
|
+
footer = self.screen.query_one(StatusFooter)
|
|
173
|
+
footer.show_notification(
|
|
174
|
+
message, severity=severity, timeout=effective_timeout
|
|
175
|
+
)
|
|
176
|
+
except Exception:
|
|
177
|
+
# Fall back to parent if footer not found
|
|
178
|
+
super().notify(
|
|
179
|
+
message, title=title, severity=severity, timeout=timeout, markup=markup
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
async def on_unmount(self) -> None:
|
|
183
|
+
"""Clean up on app exit."""
|
|
184
|
+
logger.info("tui_app_shutting_down")
|
|
185
|
+
await self.store.close()
|
|
186
|
+
logger.info("tui_app_shutdown_complete")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def run_app(api_url: str, api_key: str) -> None:
|
|
190
|
+
"""Run the Alloy Runtime Terminal app.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
api_url: Base API URL for the server
|
|
194
|
+
api_key: API key for authentication
|
|
195
|
+
"""
|
|
196
|
+
logger.info("tui_app_starting", api_url=api_url)
|
|
197
|
+
app = AlloyRuntimeApp(api_url=api_url, api_key=api_key)
|
|
198
|
+
app.run()
|
|
199
|
+
logger.info("tui_app_exited")
|
cli/tui/app_store.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Simple application store for shared state.
|
|
2
|
+
|
|
3
|
+
This module provides a minimal store that holds:
|
|
4
|
+
- API credentials (read-only config)
|
|
5
|
+
- Shared ApiClient instance (lazy initialization)
|
|
6
|
+
- Agent cache for cross-screen sharing
|
|
7
|
+
|
|
8
|
+
This replaces the previous ELM-style architecture with Textual's
|
|
9
|
+
recommended "App as Store" pattern - simple and direct.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
13
|
+
from alloy_runtime_types.dtos.agents import AgentSummary
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AppStore:
|
|
17
|
+
"""Simple app-wide store for shared state.
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
store = AppStore(api_url="...", api_key="...")
|
|
21
|
+
client = await store.get_client()
|
|
22
|
+
|
|
23
|
+
Screens access via self.app.store (Textual's recommended pattern).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, api_url: str, api_key: str) -> None:
|
|
27
|
+
"""Initialize the store.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
api_url: Base URL for the API server
|
|
31
|
+
api_key: API key for authentication
|
|
32
|
+
"""
|
|
33
|
+
self.api_url = api_url.rstrip("/")
|
|
34
|
+
self.api_key = api_key
|
|
35
|
+
self._client: ApiClient | None = None
|
|
36
|
+
self._client_entered: bool = False
|
|
37
|
+
|
|
38
|
+
# Cross-screen cache for agent picker in chat
|
|
39
|
+
self.agent_cache: list[AgentSummary] = []
|
|
40
|
+
|
|
41
|
+
async def get_client(self) -> ApiClient:
|
|
42
|
+
"""Get the shared server client instance.
|
|
43
|
+
|
|
44
|
+
Creates and connects on first use, reuses thereafter.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Connected ApiClient instance
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
Exception: If connection fails
|
|
51
|
+
"""
|
|
52
|
+
if self._client is None:
|
|
53
|
+
self._client = ApiClient(
|
|
54
|
+
base_url=self.api_url,
|
|
55
|
+
api_key=self.api_key,
|
|
56
|
+
timeout=30.0,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
if not self._client_entered:
|
|
60
|
+
await self._client.__aenter__()
|
|
61
|
+
self._client_entered = True
|
|
62
|
+
|
|
63
|
+
return self._client
|
|
64
|
+
|
|
65
|
+
async def close(self) -> None:
|
|
66
|
+
"""Close the client connection.
|
|
67
|
+
|
|
68
|
+
Should be called when the application exits.
|
|
69
|
+
"""
|
|
70
|
+
if self._client and self._client_entered:
|
|
71
|
+
await self._client.__aexit__(None, None, None)
|
|
72
|
+
self._client_entered = False
|
|
73
|
+
self._client = None
|
cli/tui/chat/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Base command protocol and utilities for chat commands.
|
|
2
|
+
|
|
3
|
+
Commands encapsulate async operations, making them:
|
|
4
|
+
- Testable in isolation with mocked dependencies
|
|
5
|
+
- Reusable across different contexts (UI, CLI, scripts)
|
|
6
|
+
- Single-responsibility focused
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Generic, Protocol, TypeVar
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T")
|
|
13
|
+
U = TypeVar("U")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Command(Protocol[T]):
|
|
17
|
+
"""Protocol for chat commands.
|
|
18
|
+
|
|
19
|
+
Commands are dataclasses that encapsulate all dependencies needed
|
|
20
|
+
to execute an async operation. They return a CommandResult with
|
|
21
|
+
the outcome.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
@dataclass
|
|
25
|
+
class SendMessageCommand:
|
|
26
|
+
client: ApiClient
|
|
27
|
+
store: ChatStore
|
|
28
|
+
session_id: UUID
|
|
29
|
+
message: str
|
|
30
|
+
|
|
31
|
+
async def execute(self) -> CommandResult[str]:
|
|
32
|
+
# ... implementation
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
async def execute(self) -> "CommandResult[T]":
|
|
36
|
+
"""Execute the command and return result."""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class CommandResult(Generic[T]):
|
|
42
|
+
"""Result wrapper for command execution.
|
|
43
|
+
|
|
44
|
+
Provides a consistent way to handle success/failure without exceptions
|
|
45
|
+
bubbling up to the UI layer.
|
|
46
|
+
|
|
47
|
+
Attributes:
|
|
48
|
+
success: Whether the command succeeded.
|
|
49
|
+
data: The result data if successful.
|
|
50
|
+
error: Error message if failed.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
success: bool
|
|
54
|
+
data: T | None = None
|
|
55
|
+
error: str | None = None
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def ok(cls: type["CommandResult[U]"], data: U) -> "CommandResult[U]":
|
|
59
|
+
"""Create a successful result."""
|
|
60
|
+
return cls(success=True, data=data)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def fail(cls: type["CommandResult[U]"], error: str) -> "CommandResult[U]":
|
|
64
|
+
"""Create a failed result."""
|
|
65
|
+
return cls(success=False, error=error)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Command for creating a new chat session."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
7
|
+
from alloy_runtime_types.dtos.sessions import CreateSessionRequest
|
|
8
|
+
from alloy_runtime_sdk.logging.config import get_logger
|
|
9
|
+
|
|
10
|
+
from cli.tui.chat.commands.base import CommandResult
|
|
11
|
+
from cli.tui.chat.store import ChatStore
|
|
12
|
+
from cli.tui.chat.types import ChatPhase
|
|
13
|
+
|
|
14
|
+
logger = get_logger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class CreateSessionResult:
|
|
19
|
+
"""Result data for create session operation.
|
|
20
|
+
|
|
21
|
+
Supports both agent mode and direct model mode.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
session_id: ID of the newly created session.
|
|
25
|
+
session_name: Name of the session.
|
|
26
|
+
agent_id: ID of the agent (agent mode).
|
|
27
|
+
agent_name: Name of the agent (agent mode).
|
|
28
|
+
provider_key: Provider key (model mode).
|
|
29
|
+
provider_model_name: Model name (model mode).
|
|
30
|
+
system_instruction: System instruction (model mode).
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
session_id: UUID
|
|
34
|
+
session_name: str | None
|
|
35
|
+
# Agent mode
|
|
36
|
+
agent_id: UUID | None = None
|
|
37
|
+
agent_name: str | None = None
|
|
38
|
+
# Model mode
|
|
39
|
+
provider_key: str | None = None
|
|
40
|
+
provider_model_name: str | None = None
|
|
41
|
+
system_instruction: str | None = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class CreateSessionCommand:
|
|
46
|
+
"""Command to create a new chat session.
|
|
47
|
+
|
|
48
|
+
Supports two modes:
|
|
49
|
+
- Agent mode: Uses agent_id/agent_name
|
|
50
|
+
- Model mode: Uses provider_key/provider_model_name/system_instruction
|
|
51
|
+
|
|
52
|
+
This command:
|
|
53
|
+
1. Transitions store to CREATING_SESSION phase
|
|
54
|
+
2. Sends create request to the API
|
|
55
|
+
3. Updates store with new session context
|
|
56
|
+
4. Clears any existing messages
|
|
57
|
+
5. Transitions back to IDLE
|
|
58
|
+
|
|
59
|
+
Attributes:
|
|
60
|
+
client: Server client for API calls.
|
|
61
|
+
store: Chat store for state management.
|
|
62
|
+
name: Optional name for the session.
|
|
63
|
+
agent_id: ID of the agent to use (agent mode).
|
|
64
|
+
agent_name: Name of the agent (agent mode).
|
|
65
|
+
provider_key: Provider key (model mode).
|
|
66
|
+
provider_model_name: Model name (model mode).
|
|
67
|
+
system_instruction: System instruction (model mode).
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
client: ApiClient
|
|
71
|
+
store: ChatStore
|
|
72
|
+
name: str | None
|
|
73
|
+
# Agent mode
|
|
74
|
+
agent_id: UUID | None = None
|
|
75
|
+
agent_name: str | None = None
|
|
76
|
+
# Model mode
|
|
77
|
+
provider_key: str | None = None
|
|
78
|
+
provider_model_name: str | None = None
|
|
79
|
+
system_instruction: str | None = None
|
|
80
|
+
|
|
81
|
+
async def execute(self) -> CommandResult[CreateSessionResult]:
|
|
82
|
+
"""Execute the create session operation.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
CommandResult with new session data on success.
|
|
86
|
+
"""
|
|
87
|
+
logger.info(
|
|
88
|
+
"create_session_starting",
|
|
89
|
+
agent_id=str(self.agent_id) if self.agent_id else None,
|
|
90
|
+
agent_name=self.agent_name,
|
|
91
|
+
model=self.provider_model_name,
|
|
92
|
+
)
|
|
93
|
+
self.store.set_phase(ChatPhase.CREATING_SESSION)
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
# Create session request - agent is optional
|
|
97
|
+
# For model mode, we don't associate an agent with the session
|
|
98
|
+
request = CreateSessionRequest(
|
|
99
|
+
name=self.name,
|
|
100
|
+
agent=str(self.agent_id) if self.agent_id else None,
|
|
101
|
+
)
|
|
102
|
+
session = await self.client.create_session(request)
|
|
103
|
+
|
|
104
|
+
# Update store with new session
|
|
105
|
+
self.store.set_session(
|
|
106
|
+
session_id=session.id,
|
|
107
|
+
session_name=self.name,
|
|
108
|
+
agent_id=self.agent_id,
|
|
109
|
+
agent_name=self.agent_name,
|
|
110
|
+
message_count=0,
|
|
111
|
+
provider_key=self.provider_key,
|
|
112
|
+
model_name=self.provider_model_name,
|
|
113
|
+
system_instruction=self.system_instruction,
|
|
114
|
+
)
|
|
115
|
+
self.store.set_messages([])
|
|
116
|
+
self.store.set_phase(ChatPhase.IDLE)
|
|
117
|
+
|
|
118
|
+
logger.info("create_session_completed", session_id=str(session.id))
|
|
119
|
+
return CommandResult[CreateSessionResult](
|
|
120
|
+
success=True,
|
|
121
|
+
data=CreateSessionResult(
|
|
122
|
+
session_id=session.id,
|
|
123
|
+
session_name=self.name,
|
|
124
|
+
agent_id=self.agent_id,
|
|
125
|
+
agent_name=self.agent_name,
|
|
126
|
+
provider_key=self.provider_key,
|
|
127
|
+
provider_model_name=self.provider_model_name,
|
|
128
|
+
system_instruction=self.system_instruction,
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
except Exception as e:
|
|
133
|
+
logger.warning("create_session_failed", error=str(e))
|
|
134
|
+
self.store.set_phase(ChatPhase.IDLE)
|
|
135
|
+
return CommandResult[CreateSessionResult](success=False, error=str(e))
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Command for loading a chat session and its messages."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
7
|
+
from alloy_runtime_types.dtos.sessions import MessageResponse
|
|
8
|
+
from alloy_runtime_sdk.logging.config import get_logger
|
|
9
|
+
|
|
10
|
+
from cli.tui.chat.commands.base import CommandResult
|
|
11
|
+
from cli.tui.chat.store import ChatStore
|
|
12
|
+
from cli.tui.chat.types import ChatPhase
|
|
13
|
+
|
|
14
|
+
logger = get_logger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class LoadSessionResult:
|
|
19
|
+
"""Result data for load session operation.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
session_id: ID of the loaded session.
|
|
23
|
+
session_name: Name of the session.
|
|
24
|
+
agent_id: ID of the agent (extracted from messages).
|
|
25
|
+
agent_name: Name of the agent (if available).
|
|
26
|
+
messages: List of messages in the session.
|
|
27
|
+
total_messages: Total message count.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
session_id: UUID
|
|
31
|
+
session_name: str | None
|
|
32
|
+
agent_id: UUID | None
|
|
33
|
+
agent_name: str | None
|
|
34
|
+
messages: list[MessageResponse]
|
|
35
|
+
total_messages: int
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class LoadSessionCommand:
|
|
40
|
+
"""Command to load a chat session and its messages.
|
|
41
|
+
|
|
42
|
+
This command:
|
|
43
|
+
1. Transitions store to LOADING_SESSION phase
|
|
44
|
+
2. Fetches session data from the API
|
|
45
|
+
3. Extracts agent info from messages
|
|
46
|
+
4. Updates store with session context and messages
|
|
47
|
+
5. Transitions back to IDLE
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
client: Server client for API calls.
|
|
51
|
+
store: Chat store for state management.
|
|
52
|
+
session_id: ID of the session to load.
|
|
53
|
+
message_limit: Maximum number of messages to fetch.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
client: ApiClient
|
|
57
|
+
store: ChatStore
|
|
58
|
+
session_id: UUID
|
|
59
|
+
message_limit: int = 100
|
|
60
|
+
|
|
61
|
+
async def execute(self) -> CommandResult[LoadSessionResult]:
|
|
62
|
+
"""Execute the load session operation.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
CommandResult with session data on success.
|
|
66
|
+
"""
|
|
67
|
+
logger.info("load_session_starting", session_id=str(self.session_id))
|
|
68
|
+
self.store.set_phase(ChatPhase.LOADING_SESSION)
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
session = await self.client.get_session(
|
|
72
|
+
self.session_id, limit=self.message_limit
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Extract agent info from messages
|
|
76
|
+
agent_id = None
|
|
77
|
+
agent_name = None
|
|
78
|
+
for msg in reversed(session.messages):
|
|
79
|
+
if msg.role == "assistant" and msg.agent_execution:
|
|
80
|
+
exec_meta = msg.agent_execution
|
|
81
|
+
if exec_meta.agent_id:
|
|
82
|
+
agent_id = exec_meta.agent_id
|
|
83
|
+
break
|
|
84
|
+
|
|
85
|
+
# Update store with session data
|
|
86
|
+
self.store.set_session(
|
|
87
|
+
session_id=self.session_id,
|
|
88
|
+
session_name=session.name,
|
|
89
|
+
agent_id=agent_id,
|
|
90
|
+
agent_name=agent_name,
|
|
91
|
+
message_count=session.total_messages,
|
|
92
|
+
)
|
|
93
|
+
self.store.set_messages(list(session.messages))
|
|
94
|
+
self.store.set_phase(ChatPhase.IDLE)
|
|
95
|
+
|
|
96
|
+
logger.info(
|
|
97
|
+
"load_session_completed",
|
|
98
|
+
session_id=str(self.session_id),
|
|
99
|
+
session_name=session.name,
|
|
100
|
+
message_count=len(session.messages),
|
|
101
|
+
)
|
|
102
|
+
return CommandResult[LoadSessionResult](
|
|
103
|
+
success=True,
|
|
104
|
+
data=LoadSessionResult(
|
|
105
|
+
session_id=self.session_id,
|
|
106
|
+
session_name=session.name,
|
|
107
|
+
agent_id=agent_id,
|
|
108
|
+
agent_name=agent_name,
|
|
109
|
+
messages=list(session.messages),
|
|
110
|
+
total_messages=session.total_messages,
|
|
111
|
+
),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
except Exception as e:
|
|
115
|
+
logger.warning(
|
|
116
|
+
"load_session_failed", session_id=str(self.session_id), error=str(e)
|
|
117
|
+
)
|
|
118
|
+
self.store.set_phase(ChatPhase.IDLE)
|
|
119
|
+
return CommandResult[LoadSessionResult](success=False, error=str(e))
|