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
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""Template update modal for editing existing template metadata.
|
|
2
|
+
|
|
3
|
+
Provides a modal screen that allows users to edit template name, description,
|
|
4
|
+
content type, visibility, and tags.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
from textual import on, work
|
|
12
|
+
from textual.app import ComposeResult
|
|
13
|
+
from textual.containers import Horizontal, VerticalScroll
|
|
14
|
+
from textual.widgets import (
|
|
15
|
+
Button,
|
|
16
|
+
Input,
|
|
17
|
+
Label,
|
|
18
|
+
RadioButton,
|
|
19
|
+
RadioSet,
|
|
20
|
+
Static,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from cli.tui.widgets.base_form_modal import BaseFormModal
|
|
24
|
+
|
|
25
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
26
|
+
from alloy_runtime_types.dtos.templates import (
|
|
27
|
+
TemplateListItemResponse,
|
|
28
|
+
UpdateTemplateRequest,
|
|
29
|
+
)
|
|
30
|
+
from alloy_runtime_types.enums.template_enums import (
|
|
31
|
+
TemplateContentType,
|
|
32
|
+
TemplateVisibility,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
from cli.infrastructure.forms.tag_picker import TagPicker
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from cli.tui.app import AlloyRuntimeApp
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class TemplateUpdateResult:
|
|
43
|
+
"""Result of successful template update."""
|
|
44
|
+
|
|
45
|
+
template_id: str
|
|
46
|
+
template_name: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TemplateUpdateModal(BaseFormModal[TemplateUpdateResult]):
|
|
50
|
+
"""Modal for updating template metadata.
|
|
51
|
+
|
|
52
|
+
Provides a form with:
|
|
53
|
+
- Editable fields: name, content type, visibility, description, tags
|
|
54
|
+
- Read-only info: ID, version count
|
|
55
|
+
|
|
56
|
+
Usage:
|
|
57
|
+
def on_template_updated(result: TemplateUpdateResult | None):
|
|
58
|
+
if result is not None:
|
|
59
|
+
self.notify(f"Updated template: {result.template_name}")
|
|
60
|
+
self._do_search("") # Refresh list
|
|
61
|
+
|
|
62
|
+
client = await self.app.store.get_client()
|
|
63
|
+
self.app.push_screen(
|
|
64
|
+
TemplateUpdateModal(client=client, template=template),
|
|
65
|
+
on_template_updated
|
|
66
|
+
)
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
app: "AlloyRuntimeApp"
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
client: ApiClient,
|
|
74
|
+
template: TemplateListItemResponse,
|
|
75
|
+
**kwargs: Any,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""Initialize the template update modal.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
client: ApiClient instance for API calls
|
|
81
|
+
template: The template to edit
|
|
82
|
+
"""
|
|
83
|
+
super().__init__(**kwargs)
|
|
84
|
+
self._client = client
|
|
85
|
+
self._template = template
|
|
86
|
+
|
|
87
|
+
def compose(self) -> ComposeResult:
|
|
88
|
+
with VerticalScroll(id="template-update-modal"):
|
|
89
|
+
yield Label(f"Edit Template: {self._template.name}", classes="modal-title")
|
|
90
|
+
|
|
91
|
+
# Template info (read-only)
|
|
92
|
+
yield Static("[bold]Template Info[/]", classes="form-section")
|
|
93
|
+
|
|
94
|
+
yield Static(
|
|
95
|
+
f"[dim]ID:[/] {str(self._template.id)[:8]}... "
|
|
96
|
+
f"[dim]Versions:[/] {self._template.latest_version_number}",
|
|
97
|
+
id="template-info",
|
|
98
|
+
classes="info-display",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Editable fields
|
|
102
|
+
yield Static("[bold]Edit Properties[/]", classes="form-section")
|
|
103
|
+
|
|
104
|
+
yield Static(
|
|
105
|
+
"Name (lowercase, dots/dashes/underscores)", classes="field-label"
|
|
106
|
+
)
|
|
107
|
+
yield Input(
|
|
108
|
+
value=self._template.name,
|
|
109
|
+
placeholder="e.g., email.welcome-header, system.default_prompt",
|
|
110
|
+
id="name-input",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
yield Static("Content Type", classes="field-label")
|
|
114
|
+
with RadioSet(id="content-type-radios"):
|
|
115
|
+
yield RadioButton(
|
|
116
|
+
"System Instruction",
|
|
117
|
+
id="type-system",
|
|
118
|
+
value=self._template.content_type_id == "system_instruction",
|
|
119
|
+
)
|
|
120
|
+
yield RadioButton(
|
|
121
|
+
"User Message",
|
|
122
|
+
id="type-user",
|
|
123
|
+
value=self._template.content_type_id == "user_message",
|
|
124
|
+
)
|
|
125
|
+
yield RadioButton(
|
|
126
|
+
"Fragment",
|
|
127
|
+
id="type-fragment",
|
|
128
|
+
value=self._template.content_type_id == "fragment",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
yield Static("Visibility", classes="field-label")
|
|
132
|
+
with RadioSet(id="visibility-radios"):
|
|
133
|
+
yield RadioButton(
|
|
134
|
+
"Private",
|
|
135
|
+
id="vis-private",
|
|
136
|
+
value=self._template.visibility_id == "private",
|
|
137
|
+
)
|
|
138
|
+
yield RadioButton(
|
|
139
|
+
"Organization",
|
|
140
|
+
id="vis-org",
|
|
141
|
+
value=self._template.visibility_id == "organization",
|
|
142
|
+
)
|
|
143
|
+
yield RadioButton(
|
|
144
|
+
"Public",
|
|
145
|
+
id="vis-public",
|
|
146
|
+
value=self._template.visibility_id == "public",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
yield Static("Description", classes="field-label")
|
|
150
|
+
yield Input(
|
|
151
|
+
value=self._template.description or "",
|
|
152
|
+
placeholder="Brief description of this template's purpose",
|
|
153
|
+
id="description-input",
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
yield Static("Tags", classes="field-label")
|
|
157
|
+
yield TagPicker(
|
|
158
|
+
client=self._client,
|
|
159
|
+
placeholder="Search tags...",
|
|
160
|
+
empty_message="No tags selected",
|
|
161
|
+
id="tag-picker",
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Error display
|
|
165
|
+
yield Static("", id="error-display", classes="error-display")
|
|
166
|
+
|
|
167
|
+
with Horizontal(classes="button-row"):
|
|
168
|
+
yield Button("Update Template", id="update-btn", variant="success")
|
|
169
|
+
yield Button("Cancel", id="cancel-btn", variant="default")
|
|
170
|
+
|
|
171
|
+
def on_mount(self) -> None:
|
|
172
|
+
"""Focus the name input and populate tags on mount."""
|
|
173
|
+
self.query_one("#name-input", Input).focus()
|
|
174
|
+
self._populate_tags()
|
|
175
|
+
|
|
176
|
+
def _populate_tags(self) -> None:
|
|
177
|
+
"""Populate the tag picker with existing tags."""
|
|
178
|
+
tag_picker = self.query_one("#tag-picker", TagPicker)
|
|
179
|
+
existing_tags = [
|
|
180
|
+
{"tag_path": t.tag_path, "display_name": t.display_name}
|
|
181
|
+
for t in self._template.tags
|
|
182
|
+
]
|
|
183
|
+
if existing_tags:
|
|
184
|
+
tag_picker.set_initial_selection(existing_tags)
|
|
185
|
+
|
|
186
|
+
@on(Button.Pressed, "#update-btn")
|
|
187
|
+
def on_update_pressed(self, event: Button.Pressed) -> None:
|
|
188
|
+
"""Handle update button press."""
|
|
189
|
+
self.action_submit()
|
|
190
|
+
|
|
191
|
+
@on(Button.Pressed, "#cancel-btn")
|
|
192
|
+
def on_cancel_pressed(self, event: Button.Pressed) -> None:
|
|
193
|
+
"""Handle cancel button press."""
|
|
194
|
+
self.dismiss(None)
|
|
195
|
+
|
|
196
|
+
def action_submit(self) -> None:
|
|
197
|
+
"""Handle form submission."""
|
|
198
|
+
try:
|
|
199
|
+
self._validate_fields()
|
|
200
|
+
self._hide_error()
|
|
201
|
+
self._finalize_submission()
|
|
202
|
+
except ValueError as e:
|
|
203
|
+
self._show_error(str(e))
|
|
204
|
+
|
|
205
|
+
def _validate_fields(self) -> None:
|
|
206
|
+
"""Validate all required fields."""
|
|
207
|
+
name = self.query_one("#name-input", Input).value.strip()
|
|
208
|
+
if not name:
|
|
209
|
+
raise ValueError("Name is required")
|
|
210
|
+
|
|
211
|
+
if not re.match(r"^[a-z0-9._-]+$", name):
|
|
212
|
+
raise ValueError(
|
|
213
|
+
"Name must be lowercase alphanumeric with dots, dashes, or underscores only"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
def _get_content_type(self) -> TemplateContentType:
|
|
217
|
+
"""Get content type from RadioSet."""
|
|
218
|
+
radios = self.query_one("#content-type-radios", RadioSet)
|
|
219
|
+
pressed = radios.pressed_button
|
|
220
|
+
if pressed is None or pressed.id == "type-system":
|
|
221
|
+
return TemplateContentType.SYSTEM_INSTRUCTION
|
|
222
|
+
elif pressed.id == "type-user":
|
|
223
|
+
return TemplateContentType.USER_MESSAGE
|
|
224
|
+
else:
|
|
225
|
+
return TemplateContentType.FRAGMENT
|
|
226
|
+
|
|
227
|
+
def _get_visibility(self) -> TemplateVisibility:
|
|
228
|
+
"""Get visibility from RadioSet."""
|
|
229
|
+
radios = self.query_one("#visibility-radios", RadioSet)
|
|
230
|
+
pressed = radios.pressed_button
|
|
231
|
+
if pressed is None or pressed.id == "vis-private":
|
|
232
|
+
return TemplateVisibility.PRIVATE
|
|
233
|
+
elif pressed.id == "vis-org":
|
|
234
|
+
return TemplateVisibility.ORGANIZATION
|
|
235
|
+
else:
|
|
236
|
+
return TemplateVisibility.PUBLIC
|
|
237
|
+
|
|
238
|
+
def _build_request(self) -> UpdateTemplateRequest:
|
|
239
|
+
"""Build the API request with only changed fields."""
|
|
240
|
+
name = self.query_one("#name-input", Input).value.strip()
|
|
241
|
+
description = self.query_one("#description-input", Input).value.strip()
|
|
242
|
+
content_type = self._get_content_type()
|
|
243
|
+
visibility = self._get_visibility()
|
|
244
|
+
|
|
245
|
+
tag_picker = self.query_one("#tag-picker", TagPicker)
|
|
246
|
+
new_tag_paths = tag_picker.selected_tags
|
|
247
|
+
old_tag_paths = [t.tag_path for t in self._template.tags]
|
|
248
|
+
|
|
249
|
+
# Only include fields that have changed
|
|
250
|
+
request_name = name if name != self._template.name else None
|
|
251
|
+
|
|
252
|
+
request_description: str | None = None
|
|
253
|
+
old_description = self._template.description or ""
|
|
254
|
+
if description != old_description:
|
|
255
|
+
request_description = description # Empty string clears description
|
|
256
|
+
|
|
257
|
+
request_content_type = (
|
|
258
|
+
content_type
|
|
259
|
+
if content_type.value != self._template.content_type_id
|
|
260
|
+
else None
|
|
261
|
+
)
|
|
262
|
+
request_visibility = (
|
|
263
|
+
visibility if visibility.value != self._template.visibility_id else None
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
# Compare tag lists (order-insensitive)
|
|
267
|
+
request_tag_paths = (
|
|
268
|
+
new_tag_paths if sorted(new_tag_paths) != sorted(old_tag_paths) else None
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
return UpdateTemplateRequest(
|
|
272
|
+
name=request_name,
|
|
273
|
+
content_type=request_content_type,
|
|
274
|
+
visibility=request_visibility,
|
|
275
|
+
description=request_description,
|
|
276
|
+
tag_paths=request_tag_paths,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
@work(exclusive=True)
|
|
280
|
+
async def _finalize_submission(self) -> None:
|
|
281
|
+
"""Submit to API."""
|
|
282
|
+
try:
|
|
283
|
+
request = self._build_request()
|
|
284
|
+
|
|
285
|
+
# Check if anything actually changed
|
|
286
|
+
if (
|
|
287
|
+
request.name is None
|
|
288
|
+
and request.content_type is None
|
|
289
|
+
and request.visibility is None
|
|
290
|
+
and request.description is None
|
|
291
|
+
and request.tag_paths is None
|
|
292
|
+
):
|
|
293
|
+
self.app.notify("No changes made", severity="information")
|
|
294
|
+
self.dismiss(None)
|
|
295
|
+
return
|
|
296
|
+
|
|
297
|
+
response = await self._client.update_template(
|
|
298
|
+
str(self._template.id), request
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
result = TemplateUpdateResult(
|
|
302
|
+
template_id=str(response.template.id),
|
|
303
|
+
template_name=response.template.name,
|
|
304
|
+
)
|
|
305
|
+
self.dismiss(result)
|
|
306
|
+
|
|
307
|
+
except Exception as e:
|
|
308
|
+
self._show_error(f"Failed to update template: {e}")
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Tool config creation modal for creating new tool configurations.
|
|
2
|
+
|
|
3
|
+
Provides a modal screen that allows users to create a new tool configuration
|
|
4
|
+
with required fields: name, tool_id, config JSON, and optional description.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from textual import on, work
|
|
12
|
+
from textual.app import ComposeResult
|
|
13
|
+
from textual.containers import Horizontal, VerticalScroll
|
|
14
|
+
from textual.widgets import (
|
|
15
|
+
Button,
|
|
16
|
+
Input,
|
|
17
|
+
Label,
|
|
18
|
+
RadioButton,
|
|
19
|
+
RadioSet,
|
|
20
|
+
Static,
|
|
21
|
+
TextArea,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from cli.infrastructure.scope_utils import get_scope_from_radioset
|
|
25
|
+
from cli.tui.widgets.base_form_modal import BaseFormModal
|
|
26
|
+
|
|
27
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
28
|
+
from alloy_runtime_types.dtos.tool_configs import CreateToolConfigRequest
|
|
29
|
+
from alloy_runtime_types.enums.ownership_scope import OwnershipScope
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class ToolConfigCreateResult:
|
|
34
|
+
"""Result of successful tool config creation."""
|
|
35
|
+
|
|
36
|
+
config_id: str
|
|
37
|
+
config_name: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ToolConfigCreateModal(BaseFormModal[ToolConfigCreateResult]):
|
|
41
|
+
"""Modal for creating a new tool configuration.
|
|
42
|
+
|
|
43
|
+
Provides a form with:
|
|
44
|
+
- Required fields: name, tool_id, config (JSON)
|
|
45
|
+
- Scope selection (user/organization/global)
|
|
46
|
+
- Optional: description
|
|
47
|
+
|
|
48
|
+
Usage:
|
|
49
|
+
def on_config_created(result: ToolConfigCreateResult | None):
|
|
50
|
+
if result is not None:
|
|
51
|
+
self.notify(f"Created config: {result.config_name}")
|
|
52
|
+
self._do_search("") # Refresh list
|
|
53
|
+
|
|
54
|
+
client = await self.app.store.get_client()
|
|
55
|
+
self.app.push_screen(
|
|
56
|
+
ToolConfigCreateModal(client=client),
|
|
57
|
+
on_config_created
|
|
58
|
+
)
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(
|
|
62
|
+
self,
|
|
63
|
+
client: ApiClient,
|
|
64
|
+
**kwargs: Any,
|
|
65
|
+
) -> None:
|
|
66
|
+
"""Initialize the tool config creation modal.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
client: ApiClient instance for API calls
|
|
70
|
+
"""
|
|
71
|
+
super().__init__(**kwargs)
|
|
72
|
+
self._client = client
|
|
73
|
+
|
|
74
|
+
def compose(self) -> ComposeResult:
|
|
75
|
+
with VerticalScroll(id="tool-config-create-modal"):
|
|
76
|
+
yield Label("Create Tool Config", classes="modal-title")
|
|
77
|
+
|
|
78
|
+
# ===== REQUIRED FIELDS =====
|
|
79
|
+
yield Static("[bold]Required[/]", classes="form-section")
|
|
80
|
+
|
|
81
|
+
yield Static("Name", classes="field-label")
|
|
82
|
+
yield Input(
|
|
83
|
+
placeholder="e.g., RAG with HyDE, Fast Web Search",
|
|
84
|
+
id="name-input",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
yield Static("Tool ID", classes="field-label")
|
|
88
|
+
yield Input(
|
|
89
|
+
placeholder="e.g., rag_search, web_search",
|
|
90
|
+
id="tool-id-input",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
yield Static("Scope", classes="field-label")
|
|
94
|
+
with RadioSet(id="scope-radios"):
|
|
95
|
+
yield RadioButton("User (personal)", id="scope-user", value=True)
|
|
96
|
+
yield RadioButton("Organization", id="scope-org")
|
|
97
|
+
yield RadioButton("Global", id="scope-global")
|
|
98
|
+
|
|
99
|
+
yield Static(
|
|
100
|
+
"Configuration (JSON object with tool parameters)",
|
|
101
|
+
classes="field-label",
|
|
102
|
+
)
|
|
103
|
+
yield TextArea(
|
|
104
|
+
id="config-textarea",
|
|
105
|
+
classes="definition-input",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# ===== OPTIONAL FIELDS =====
|
|
109
|
+
yield Static("[bold]Optional[/]", classes="form-section")
|
|
110
|
+
|
|
111
|
+
yield Static("Description", classes="field-label")
|
|
112
|
+
yield Input(
|
|
113
|
+
placeholder="Brief description of this configuration",
|
|
114
|
+
id="description-input",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Error display
|
|
118
|
+
yield Static("", id="error-display", classes="error-display")
|
|
119
|
+
|
|
120
|
+
with Horizontal(classes="button-row"):
|
|
121
|
+
yield Button("Create Config", id="create-btn", variant="success")
|
|
122
|
+
yield Button("Cancel", id="cancel-btn", variant="default")
|
|
123
|
+
|
|
124
|
+
def on_mount(self) -> None:
|
|
125
|
+
"""Focus the name input and set default config on mount."""
|
|
126
|
+
self.query_one("#config-textarea", TextArea).text = "{}"
|
|
127
|
+
self.query_one("#name-input", Input).focus()
|
|
128
|
+
|
|
129
|
+
@on(Button.Pressed, "#create-btn")
|
|
130
|
+
def on_create_pressed(self, event: Button.Pressed) -> None:
|
|
131
|
+
"""Handle create button press."""
|
|
132
|
+
self.action_submit()
|
|
133
|
+
|
|
134
|
+
@on(Button.Pressed, "#cancel-btn")
|
|
135
|
+
def on_cancel_pressed(self, event: Button.Pressed) -> None:
|
|
136
|
+
"""Handle cancel button press."""
|
|
137
|
+
self.dismiss(None)
|
|
138
|
+
|
|
139
|
+
def action_submit(self) -> None:
|
|
140
|
+
"""Handle form submission."""
|
|
141
|
+
try:
|
|
142
|
+
self._validate_fields()
|
|
143
|
+
self._hide_error()
|
|
144
|
+
self._finalize_submission()
|
|
145
|
+
except ValueError as e:
|
|
146
|
+
self._show_error(str(e))
|
|
147
|
+
|
|
148
|
+
def _validate_fields(self) -> None:
|
|
149
|
+
"""Validate all required fields."""
|
|
150
|
+
name = self.query_one("#name-input", Input).value.strip()
|
|
151
|
+
if not name:
|
|
152
|
+
raise ValueError("Name is required")
|
|
153
|
+
if len(name) > 255:
|
|
154
|
+
raise ValueError("Name must be 255 characters or less")
|
|
155
|
+
|
|
156
|
+
tool_id = self.query_one("#tool-id-input", Input).value.strip()
|
|
157
|
+
if not tool_id:
|
|
158
|
+
raise ValueError("Tool ID is required")
|
|
159
|
+
|
|
160
|
+
config_text = self.query_one("#config-textarea", TextArea).text.strip()
|
|
161
|
+
if not config_text:
|
|
162
|
+
raise ValueError("Configuration is required")
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
config = json.loads(config_text)
|
|
166
|
+
if not isinstance(config, dict):
|
|
167
|
+
raise ValueError(
|
|
168
|
+
"Configuration must be a JSON object (not array/primitive)"
|
|
169
|
+
)
|
|
170
|
+
except json.JSONDecodeError as e:
|
|
171
|
+
raise ValueError(f"Invalid JSON in configuration: {e.msg}")
|
|
172
|
+
|
|
173
|
+
def _get_scope(self) -> OwnershipScope:
|
|
174
|
+
"""Get scope from RadioSet."""
|
|
175
|
+
return get_scope_from_radioset(self.query_one("#scope-radios", RadioSet))
|
|
176
|
+
|
|
177
|
+
def _build_request(self) -> CreateToolConfigRequest:
|
|
178
|
+
"""Build the API request."""
|
|
179
|
+
name = self.query_one("#name-input", Input).value.strip()
|
|
180
|
+
tool_id = self.query_one("#tool-id-input", Input).value.strip()
|
|
181
|
+
config_text = self.query_one("#config-textarea", TextArea).text.strip()
|
|
182
|
+
config = json.loads(config_text)
|
|
183
|
+
description = self.query_one("#description-input", Input).value.strip() or None
|
|
184
|
+
|
|
185
|
+
return CreateToolConfigRequest(
|
|
186
|
+
name=name,
|
|
187
|
+
tool_id=tool_id,
|
|
188
|
+
config=config,
|
|
189
|
+
description=description,
|
|
190
|
+
scope=self._get_scope(),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
@work(exclusive=True)
|
|
194
|
+
async def _finalize_submission(self) -> None:
|
|
195
|
+
"""Submit to API."""
|
|
196
|
+
try:
|
|
197
|
+
request = self._build_request()
|
|
198
|
+
response = await self._client.create_tool_config(request)
|
|
199
|
+
|
|
200
|
+
result = ToolConfigCreateResult(
|
|
201
|
+
config_id=str(response.id),
|
|
202
|
+
config_name=response.name,
|
|
203
|
+
)
|
|
204
|
+
self.dismiss(result)
|
|
205
|
+
|
|
206
|
+
except Exception as e:
|
|
207
|
+
error_msg = str(e)
|
|
208
|
+
# Provide user-friendly error messages
|
|
209
|
+
if "409" in error_msg or "conflict" in error_msg.lower():
|
|
210
|
+
self._show_error(
|
|
211
|
+
"A tool config with this name already exists in this scope"
|
|
212
|
+
)
|
|
213
|
+
elif "validation" in error_msg.lower():
|
|
214
|
+
self._show_error(f"Invalid configuration: {error_msg}")
|
|
215
|
+
else:
|
|
216
|
+
self._show_error(f"Failed to create tool config: {error_msg}")
|