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,384 @@
|
|
|
1
|
+
"""Agent tool editor widget for configuring a single tool instance.
|
|
2
|
+
|
|
3
|
+
Provides a compound widget for editing tool configuration including:
|
|
4
|
+
- Tool selection
|
|
5
|
+
- Alias (defaults to tool_id)
|
|
6
|
+
- Config mode: none, inline JSON, or saved config reference
|
|
7
|
+
- Inline config JSON textarea with parameter_schema display
|
|
8
|
+
- Tool config picker for referencing saved configs
|
|
9
|
+
- Enable/disable toggle
|
|
10
|
+
- LLM instruction input
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
from typing import Any
|
|
16
|
+
from uuid import UUID
|
|
17
|
+
|
|
18
|
+
from textual import on, work
|
|
19
|
+
from textual.app import ComposeResult
|
|
20
|
+
from textual.containers import Horizontal, Vertical
|
|
21
|
+
from textual.message import Message
|
|
22
|
+
from textual.widget import Widget
|
|
23
|
+
from textual.widgets import (
|
|
24
|
+
Button,
|
|
25
|
+
Checkbox,
|
|
26
|
+
Input,
|
|
27
|
+
RadioButton,
|
|
28
|
+
RadioSet,
|
|
29
|
+
Static,
|
|
30
|
+
TextArea,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
34
|
+
from alloy_runtime_types.dtos.agents import AgentToolConfig, AgentToolResponse
|
|
35
|
+
from alloy_runtime_types.dtos.tool_configs import ToolConfigSummary
|
|
36
|
+
from alloy_runtime_types.dtos.tools import ToolResponse
|
|
37
|
+
|
|
38
|
+
from cli.infrastructure.forms.tool_config_picker import ToolConfigPicker
|
|
39
|
+
from cli.infrastructure.forms.tool_picker import ToolPicker
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AgentToolEditor(Widget):
|
|
43
|
+
"""Editor widget for a single agent tool configuration.
|
|
44
|
+
|
|
45
|
+
Provides UI for configuring a tool instance with support for:
|
|
46
|
+
- Tool selection from available tools
|
|
47
|
+
- Custom alias (enables multiple instances of same tool)
|
|
48
|
+
- Three config modes: none, inline JSON, saved config reference
|
|
49
|
+
- LLM instruction for per-agent hints
|
|
50
|
+
|
|
51
|
+
Usage:
|
|
52
|
+
editor = AgentToolEditor(client=client, id="tool-editor-1")
|
|
53
|
+
# Get the configured tool
|
|
54
|
+
config = editor.get_tool_config() # AgentToolConfig | None
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
DEFAULT_CLASSES = "tool-editor"
|
|
58
|
+
|
|
59
|
+
class ToolChanged(Message):
|
|
60
|
+
"""Posted when tool configuration changes."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, editor: "AgentToolEditor") -> None:
|
|
63
|
+
self.editor = editor
|
|
64
|
+
super().__init__()
|
|
65
|
+
|
|
66
|
+
class RemoveRequested(Message):
|
|
67
|
+
"""Posted when user requests removal of this editor."""
|
|
68
|
+
|
|
69
|
+
def __init__(self, editor: "AgentToolEditor") -> None:
|
|
70
|
+
self.editor = editor
|
|
71
|
+
super().__init__()
|
|
72
|
+
|
|
73
|
+
def __init__(
|
|
74
|
+
self,
|
|
75
|
+
client: ApiClient,
|
|
76
|
+
tool_order: int = 0,
|
|
77
|
+
**kwargs: Any,
|
|
78
|
+
) -> None:
|
|
79
|
+
"""Initialize the agent tool editor.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
client: ApiClient instance for API calls
|
|
83
|
+
tool_order: Order of this tool in the agent's tool list
|
|
84
|
+
"""
|
|
85
|
+
super().__init__(**kwargs)
|
|
86
|
+
self._client = client
|
|
87
|
+
self._tool_order = tool_order
|
|
88
|
+
self._selected_tool: ToolResponse | None = None
|
|
89
|
+
|
|
90
|
+
def compose(self) -> ComposeResult:
|
|
91
|
+
with Vertical(classes="tool-editor-content"):
|
|
92
|
+
# Header with title and remove button
|
|
93
|
+
with Horizontal(classes="tool-header"):
|
|
94
|
+
yield Static(
|
|
95
|
+
f"Tool #{self._tool_order + 1}",
|
|
96
|
+
classes="tool-title",
|
|
97
|
+
id="tool-title",
|
|
98
|
+
)
|
|
99
|
+
yield Button("Remove", id="remove-btn", variant="error")
|
|
100
|
+
|
|
101
|
+
# Tool selection
|
|
102
|
+
yield Static("Tool *", classes="field-label")
|
|
103
|
+
yield ToolPicker(client=self._client, id="tool-picker")
|
|
104
|
+
|
|
105
|
+
# Alias
|
|
106
|
+
yield Static("Alias (defaults to tool ID)", classes="field-label")
|
|
107
|
+
yield Input(placeholder="e.g., rag-testimonials", id="alias-input")
|
|
108
|
+
|
|
109
|
+
# Config mode selection
|
|
110
|
+
yield Static("Configuration", classes="field-label")
|
|
111
|
+
with RadioSet(id="config-mode-radios"):
|
|
112
|
+
yield RadioButton("No configuration", id="mode-none", value=True)
|
|
113
|
+
yield RadioButton("Inline config (JSON)", id="mode-inline")
|
|
114
|
+
yield RadioButton("Use saved config", id="mode-reference")
|
|
115
|
+
|
|
116
|
+
# Inline config section (hidden by default)
|
|
117
|
+
with Vertical(id="inline-config-section", classes="config-section hidden"):
|
|
118
|
+
yield Static(
|
|
119
|
+
"Parameter Schema (reference):", classes="field-label schema-label"
|
|
120
|
+
)
|
|
121
|
+
yield TextArea(id="schema-display", read_only=True)
|
|
122
|
+
yield Static("Config (JSON):", classes="field-label")
|
|
123
|
+
yield TextArea(id="config-input", language="json")
|
|
124
|
+
|
|
125
|
+
# Tool config reference section (hidden by default)
|
|
126
|
+
with Vertical(
|
|
127
|
+
id="config-reference-section", classes="config-section hidden"
|
|
128
|
+
):
|
|
129
|
+
yield Static("Select saved config:", classes="field-label")
|
|
130
|
+
yield ToolConfigPicker(
|
|
131
|
+
client=self._client,
|
|
132
|
+
tool_id=None,
|
|
133
|
+
id="tool-config-picker",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Enable toggle
|
|
137
|
+
yield Checkbox("Enabled", value=True, id="enabled-checkbox")
|
|
138
|
+
|
|
139
|
+
# LLM instruction
|
|
140
|
+
yield Static("LLM Instruction (optional)", classes="field-label")
|
|
141
|
+
yield TextArea(
|
|
142
|
+
id="llm-instruction-input",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
@on(Button.Pressed, "#remove-btn")
|
|
146
|
+
def on_remove_pressed(self, event: Button.Pressed) -> None:
|
|
147
|
+
"""Handle remove button press."""
|
|
148
|
+
event.stop()
|
|
149
|
+
self.post_message(self.RemoveRequested(self))
|
|
150
|
+
|
|
151
|
+
@on(ToolPicker.SelectionChanged)
|
|
152
|
+
def on_tool_selected(self, event: ToolPicker.SelectionChanged) -> None:
|
|
153
|
+
"""Handle tool selection change."""
|
|
154
|
+
event.stop()
|
|
155
|
+
self._selected_tool = event.selected_item
|
|
156
|
+
|
|
157
|
+
# Update alias placeholder
|
|
158
|
+
alias_input = self.query_one("#alias-input", Input)
|
|
159
|
+
if self._selected_tool:
|
|
160
|
+
alias_input.placeholder = f"Default: {self._selected_tool.id}"
|
|
161
|
+
else:
|
|
162
|
+
alias_input.placeholder = "e.g., rag-testimonials"
|
|
163
|
+
|
|
164
|
+
# Update schema display
|
|
165
|
+
self._update_schema_display()
|
|
166
|
+
|
|
167
|
+
# Update tool config picker filter
|
|
168
|
+
config_picker = self.query_one("#tool-config-picker", ToolConfigPicker)
|
|
169
|
+
config_picker.tool_id = self._selected_tool.id if self._selected_tool else None
|
|
170
|
+
|
|
171
|
+
# Post change event
|
|
172
|
+
self.post_message(self.ToolChanged(self))
|
|
173
|
+
|
|
174
|
+
@on(RadioSet.Changed, "#config-mode-radios")
|
|
175
|
+
def on_config_mode_changed(self, event: RadioSet.Changed) -> None:
|
|
176
|
+
"""Handle config mode change."""
|
|
177
|
+
event.stop()
|
|
178
|
+
self._update_config_sections()
|
|
179
|
+
self.post_message(self.ToolChanged(self))
|
|
180
|
+
|
|
181
|
+
def _update_config_sections(self) -> None:
|
|
182
|
+
"""Show/hide config sections based on selected mode."""
|
|
183
|
+
radios = self.query_one("#config-mode-radios", RadioSet)
|
|
184
|
+
pressed = radios.pressed_button
|
|
185
|
+
|
|
186
|
+
inline_section = self.query_one("#inline-config-section", Vertical)
|
|
187
|
+
reference_section = self.query_one("#config-reference-section", Vertical)
|
|
188
|
+
|
|
189
|
+
if pressed and pressed.id == "mode-inline":
|
|
190
|
+
inline_section.remove_class("hidden")
|
|
191
|
+
reference_section.add_class("hidden")
|
|
192
|
+
elif pressed and pressed.id == "mode-reference":
|
|
193
|
+
inline_section.add_class("hidden")
|
|
194
|
+
reference_section.remove_class("hidden")
|
|
195
|
+
else:
|
|
196
|
+
inline_section.add_class("hidden")
|
|
197
|
+
reference_section.add_class("hidden")
|
|
198
|
+
|
|
199
|
+
def _update_schema_display(self) -> None:
|
|
200
|
+
"""Update the schema display with selected tool's parameter_schema."""
|
|
201
|
+
schema_display = self.query_one("#schema-display", TextArea)
|
|
202
|
+
|
|
203
|
+
if self._selected_tool and self._selected_tool.parameter_schema:
|
|
204
|
+
schema_json = json.dumps(self._selected_tool.parameter_schema, indent=2)
|
|
205
|
+
schema_display.text = schema_json
|
|
206
|
+
else:
|
|
207
|
+
schema_display.text = "(This tool has no configurable parameters)"
|
|
208
|
+
|
|
209
|
+
def get_tool_config(self) -> AgentToolConfig | None:
|
|
210
|
+
"""Get the current tool configuration.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
AgentToolConfig if a tool is selected and valid, None otherwise
|
|
214
|
+
"""
|
|
215
|
+
tool_picker = self.query_one("#tool-picker", ToolPicker)
|
|
216
|
+
if not tool_picker.selected_tool:
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
tool_id = tool_picker.selected_tool.id
|
|
220
|
+
alias_input = self.query_one("#alias-input", Input)
|
|
221
|
+
alias = alias_input.value.strip() or None
|
|
222
|
+
|
|
223
|
+
# Get config mode
|
|
224
|
+
radios = self.query_one("#config-mode-radios", RadioSet)
|
|
225
|
+
pressed = radios.pressed_button
|
|
226
|
+
config_mode = pressed.id if pressed else "mode-none"
|
|
227
|
+
|
|
228
|
+
config: dict[str, Any] | None = None
|
|
229
|
+
tool_config_id: UUID | None = None
|
|
230
|
+
|
|
231
|
+
if config_mode == "mode-inline":
|
|
232
|
+
config_input = self.query_one("#config-input", TextArea)
|
|
233
|
+
config_text = config_input.text.strip()
|
|
234
|
+
if config_text:
|
|
235
|
+
try:
|
|
236
|
+
config = json.loads(config_text)
|
|
237
|
+
except json.JSONDecodeError:
|
|
238
|
+
# Invalid JSON, will be caught by validation
|
|
239
|
+
config = None
|
|
240
|
+
elif config_mode == "mode-reference":
|
|
241
|
+
config_picker = self.query_one("#tool-config-picker", ToolConfigPicker)
|
|
242
|
+
if config_picker.selected_config:
|
|
243
|
+
tool_config_id = config_picker.selected_config.id
|
|
244
|
+
|
|
245
|
+
enabled_checkbox = self.query_one("#enabled-checkbox", Checkbox)
|
|
246
|
+
llm_instruction_input = self.query_one("#llm-instruction-input", TextArea)
|
|
247
|
+
llm_instruction = llm_instruction_input.text.strip() or None
|
|
248
|
+
|
|
249
|
+
return AgentToolConfig(
|
|
250
|
+
tool_id=tool_id,
|
|
251
|
+
tool_alias=alias,
|
|
252
|
+
config=config,
|
|
253
|
+
tool_config_id=tool_config_id,
|
|
254
|
+
is_enabled=enabled_checkbox.value,
|
|
255
|
+
tool_order=self._tool_order,
|
|
256
|
+
llm_instruction=llm_instruction,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
def validate(self) -> str | None:
|
|
260
|
+
"""Validate the current configuration.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Error message if invalid, None if valid
|
|
264
|
+
"""
|
|
265
|
+
tool_picker = self.query_one("#tool-picker", ToolPicker)
|
|
266
|
+
if not tool_picker.selected_tool:
|
|
267
|
+
return f"Tool #{self._tool_order + 1}: No tool selected"
|
|
268
|
+
|
|
269
|
+
# Get config mode
|
|
270
|
+
radios = self.query_one("#config-mode-radios", RadioSet)
|
|
271
|
+
pressed = radios.pressed_button
|
|
272
|
+
config_mode = pressed.id if pressed else "mode-none"
|
|
273
|
+
|
|
274
|
+
if config_mode == "mode-inline":
|
|
275
|
+
config_input = self.query_one("#config-input", TextArea)
|
|
276
|
+
config_text = config_input.text.strip()
|
|
277
|
+
if config_text:
|
|
278
|
+
try:
|
|
279
|
+
json.loads(config_text)
|
|
280
|
+
except json.JSONDecodeError as e:
|
|
281
|
+
return (
|
|
282
|
+
f"Tool #{self._tool_order + 1}: Invalid JSON config - {e.msg}"
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
def get_alias(self) -> str:
|
|
288
|
+
"""Get the effective alias for this tool."""
|
|
289
|
+
alias_input = self.query_one("#alias-input", Input)
|
|
290
|
+
alias = alias_input.value.strip()
|
|
291
|
+
if alias:
|
|
292
|
+
return alias
|
|
293
|
+
tool_picker = self.query_one("#tool-picker", ToolPicker)
|
|
294
|
+
if tool_picker.selected_tool:
|
|
295
|
+
return tool_picker.selected_tool.id
|
|
296
|
+
return ""
|
|
297
|
+
|
|
298
|
+
def set_tool_order(self, order: int) -> None:
|
|
299
|
+
"""Update the tool order and title."""
|
|
300
|
+
self._tool_order = order
|
|
301
|
+
title = self.query_one("#tool-title", Static)
|
|
302
|
+
title.update(f"Tool #{order + 1}")
|
|
303
|
+
|
|
304
|
+
def populate_from_response(self, tool: AgentToolResponse) -> None:
|
|
305
|
+
"""Populate the editor from an AgentToolResponse.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
tool: Existing tool configuration to load
|
|
309
|
+
"""
|
|
310
|
+
self._populate_from_response_async(tool)
|
|
311
|
+
|
|
312
|
+
@work(exclusive=True)
|
|
313
|
+
async def _populate_from_response_async(self, tool: AgentToolResponse) -> None:
|
|
314
|
+
"""Async population to fetch full tool details."""
|
|
315
|
+
# Fetch full tool details to get parameter_schema
|
|
316
|
+
try:
|
|
317
|
+
tool_response = await self._client.get_tool(tool.tool_id)
|
|
318
|
+
self._selected_tool = tool_response
|
|
319
|
+
except Exception:
|
|
320
|
+
# Create minimal tool response if fetch fails
|
|
321
|
+
self._selected_tool = ToolResponse(
|
|
322
|
+
id=tool.tool_id,
|
|
323
|
+
description="",
|
|
324
|
+
parameter_schema=None,
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Set tool picker
|
|
328
|
+
tool_picker = self.query_one("#tool-picker", ToolPicker)
|
|
329
|
+
tool_picker.set_initial_tool(self._selected_tool)
|
|
330
|
+
|
|
331
|
+
# Set alias
|
|
332
|
+
alias_input = self.query_one("#alias-input", Input)
|
|
333
|
+
if tool.tool_alias and tool.tool_alias != tool.tool_id:
|
|
334
|
+
alias_input.value = tool.tool_alias
|
|
335
|
+
|
|
336
|
+
# Set config mode and values
|
|
337
|
+
if tool.config:
|
|
338
|
+
# Inline config mode
|
|
339
|
+
radio = self.query_one("#mode-inline", RadioButton)
|
|
340
|
+
radio.value = True
|
|
341
|
+
config_input = self.query_one("#config-input", TextArea)
|
|
342
|
+
config_input.text = json.dumps(tool.config, indent=2)
|
|
343
|
+
elif tool.tool_config_id:
|
|
344
|
+
# Reference mode
|
|
345
|
+
radio = self.query_one("#mode-reference", RadioButton)
|
|
346
|
+
radio.value = True
|
|
347
|
+
# Fetch and set tool config
|
|
348
|
+
config_picker = self.query_one("#tool-config-picker", ToolConfigPicker)
|
|
349
|
+
config_picker.tool_id = tool.tool_id
|
|
350
|
+
if tool.tool_config_name:
|
|
351
|
+
# Create a minimal summary for display
|
|
352
|
+
summary = ToolConfigSummary(
|
|
353
|
+
id=tool.tool_config_id,
|
|
354
|
+
name=tool.tool_config_name,
|
|
355
|
+
slug="",
|
|
356
|
+
tool_id=tool.tool_id,
|
|
357
|
+
description=None,
|
|
358
|
+
organization_id=None,
|
|
359
|
+
user_id=None,
|
|
360
|
+
created_at=datetime.now(timezone.utc),
|
|
361
|
+
updated_at=datetime.now(timezone.utc),
|
|
362
|
+
)
|
|
363
|
+
config_picker.set_initial_config(summary)
|
|
364
|
+
else:
|
|
365
|
+
# No config mode (default)
|
|
366
|
+
radio = self.query_one("#mode-none", RadioButton)
|
|
367
|
+
radio.value = True
|
|
368
|
+
|
|
369
|
+
# Update visibility
|
|
370
|
+
self._update_config_sections()
|
|
371
|
+
self._update_schema_display()
|
|
372
|
+
|
|
373
|
+
# Set enabled
|
|
374
|
+
enabled_checkbox = self.query_one("#enabled-checkbox", Checkbox)
|
|
375
|
+
enabled_checkbox.value = tool.is_enabled
|
|
376
|
+
|
|
377
|
+
# Set LLM instruction
|
|
378
|
+
if tool.llm_instruction:
|
|
379
|
+
llm_input = self.query_one("#llm-instruction-input", TextArea)
|
|
380
|
+
llm_input.text = tool.llm_instruction
|
|
381
|
+
|
|
382
|
+
# Update order
|
|
383
|
+
self._tool_order = tool.tool_order
|
|
384
|
+
self.set_tool_order(tool.tool_order)
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Agent tools manager widget for managing a list of tool configurations.
|
|
2
|
+
|
|
3
|
+
Provides a compound widget for managing multiple tool configurations including:
|
|
4
|
+
- Add tool button
|
|
5
|
+
- List of AgentToolEditor widgets
|
|
6
|
+
- Removal of individual tools
|
|
7
|
+
- Validation of unique aliases
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from textual import on
|
|
13
|
+
from textual.app import ComposeResult
|
|
14
|
+
from textual.containers import Vertical, VerticalScroll
|
|
15
|
+
from textual.message import Message
|
|
16
|
+
from textual.widget import Widget
|
|
17
|
+
from textual.widgets import Button, Static
|
|
18
|
+
|
|
19
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
20
|
+
from alloy_runtime_types.dtos.agents import AgentToolConfig, AgentToolResponse
|
|
21
|
+
|
|
22
|
+
from cli.infrastructure.forms.agent_tool_editor import AgentToolEditor
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AgentToolsManager(Widget):
|
|
26
|
+
"""Manager widget for a list of agent tool configurations.
|
|
27
|
+
|
|
28
|
+
Provides UI for managing multiple tool instances with:
|
|
29
|
+
- Add tool button
|
|
30
|
+
- List of AgentToolEditor widgets
|
|
31
|
+
- Removal of individual tools
|
|
32
|
+
- Validation of unique aliases
|
|
33
|
+
|
|
34
|
+
Usage:
|
|
35
|
+
manager = AgentToolsManager(client=client, id="tools-manager")
|
|
36
|
+
# Get all configured tools
|
|
37
|
+
tools = manager.configured_tools # list[AgentToolConfig]
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
DEFAULT_CLASSES = "tools-manager"
|
|
41
|
+
|
|
42
|
+
class ToolsChanged(Message):
|
|
43
|
+
"""Posted when the tools list changes."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, tools: list[AgentToolConfig]) -> None:
|
|
46
|
+
self.tools = tools
|
|
47
|
+
super().__init__()
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
client: ApiClient,
|
|
52
|
+
**kwargs: Any,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Initialize the agent tools manager.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
client: ApiClient instance for API calls
|
|
58
|
+
"""
|
|
59
|
+
super().__init__(**kwargs)
|
|
60
|
+
self._client = client
|
|
61
|
+
self._editor_count = 0
|
|
62
|
+
|
|
63
|
+
def compose(self) -> ComposeResult:
|
|
64
|
+
with Vertical(classes="tools-manager-content"):
|
|
65
|
+
yield Button("+ Add Tool", id="add-tool-btn", variant="primary")
|
|
66
|
+
yield Static("No tools configured", id="empty-message")
|
|
67
|
+
yield VerticalScroll(id="tools-list")
|
|
68
|
+
|
|
69
|
+
@on(Button.Pressed, "#add-tool-btn")
|
|
70
|
+
def on_add_tool_pressed(self, event: Button.Pressed) -> None:
|
|
71
|
+
"""Handle add tool button press."""
|
|
72
|
+
event.stop()
|
|
73
|
+
self._add_tool_editor()
|
|
74
|
+
|
|
75
|
+
@on(AgentToolEditor.RemoveRequested)
|
|
76
|
+
def on_tool_remove_requested(self, event: AgentToolEditor.RemoveRequested) -> None:
|
|
77
|
+
"""Handle tool removal request."""
|
|
78
|
+
event.stop()
|
|
79
|
+
self._remove_tool_editor(event.editor)
|
|
80
|
+
|
|
81
|
+
@on(AgentToolEditor.ToolChanged)
|
|
82
|
+
def on_tool_changed(self, event: AgentToolEditor.ToolChanged) -> None:
|
|
83
|
+
"""Handle tool configuration change."""
|
|
84
|
+
event.stop()
|
|
85
|
+
self.post_message(self.ToolsChanged(self.configured_tools))
|
|
86
|
+
|
|
87
|
+
def _add_tool_editor(self) -> None:
|
|
88
|
+
"""Add a new tool editor to the list."""
|
|
89
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
90
|
+
editor = AgentToolEditor(
|
|
91
|
+
client=self._client,
|
|
92
|
+
tool_order=self._editor_count,
|
|
93
|
+
id=f"tool-editor-{self._editor_count}",
|
|
94
|
+
)
|
|
95
|
+
tools_list.mount(editor)
|
|
96
|
+
self._editor_count += 1
|
|
97
|
+
self._update_empty_message()
|
|
98
|
+
self.post_message(self.ToolsChanged(self.configured_tools))
|
|
99
|
+
|
|
100
|
+
def _remove_tool_editor(self, editor: AgentToolEditor) -> None:
|
|
101
|
+
"""Remove a tool editor from the list."""
|
|
102
|
+
editor.remove()
|
|
103
|
+
self._renumber_editors()
|
|
104
|
+
self._update_empty_message()
|
|
105
|
+
self.post_message(self.ToolsChanged(self.configured_tools))
|
|
106
|
+
|
|
107
|
+
def _renumber_editors(self) -> None:
|
|
108
|
+
"""Renumber all editors after removal."""
|
|
109
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
110
|
+
for i, editor in enumerate(tools_list.query(AgentToolEditor)):
|
|
111
|
+
editor.set_tool_order(i)
|
|
112
|
+
|
|
113
|
+
def _update_empty_message(self) -> None:
|
|
114
|
+
"""Show/hide empty message based on editor count."""
|
|
115
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
116
|
+
empty_message = self.query_one("#empty-message", Static)
|
|
117
|
+
editors = list(tools_list.query(AgentToolEditor))
|
|
118
|
+
if editors:
|
|
119
|
+
empty_message.add_class("hidden")
|
|
120
|
+
else:
|
|
121
|
+
empty_message.remove_class("hidden")
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def configured_tools(self) -> list[AgentToolConfig]:
|
|
125
|
+
"""Get all configured tools.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
List of AgentToolConfig from all editors with valid selections
|
|
129
|
+
"""
|
|
130
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
131
|
+
configs: list[AgentToolConfig] = []
|
|
132
|
+
for i, editor in enumerate(tools_list.query(AgentToolEditor)):
|
|
133
|
+
config = editor.get_tool_config()
|
|
134
|
+
if config:
|
|
135
|
+
# Update tool_order to match current position
|
|
136
|
+
config.tool_order = i
|
|
137
|
+
configs.append(config)
|
|
138
|
+
return configs
|
|
139
|
+
|
|
140
|
+
def validate_aliases(self) -> str | None:
|
|
141
|
+
"""Validate that all tool aliases are unique.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Error message if duplicates found, None if all unique
|
|
145
|
+
"""
|
|
146
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
147
|
+
aliases: dict[str, int] = {}
|
|
148
|
+
|
|
149
|
+
for i, editor in enumerate(tools_list.query(AgentToolEditor)):
|
|
150
|
+
alias = editor.get_alias()
|
|
151
|
+
if not alias:
|
|
152
|
+
continue
|
|
153
|
+
if alias in aliases:
|
|
154
|
+
return (
|
|
155
|
+
f"Duplicate tool alias '{alias}' found in tools "
|
|
156
|
+
f"#{aliases[alias] + 1} and #{i + 1}"
|
|
157
|
+
)
|
|
158
|
+
aliases[alias] = i
|
|
159
|
+
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
def validate_all(self) -> str | None:
|
|
163
|
+
"""Validate all tool editors.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
First error message found, or None if all valid
|
|
167
|
+
"""
|
|
168
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
169
|
+
|
|
170
|
+
# Validate individual editors
|
|
171
|
+
for editor in tools_list.query(AgentToolEditor):
|
|
172
|
+
error = editor.validate()
|
|
173
|
+
if error:
|
|
174
|
+
return error
|
|
175
|
+
|
|
176
|
+
# Validate unique aliases
|
|
177
|
+
return self.validate_aliases()
|
|
178
|
+
|
|
179
|
+
def set_initial_tools(self, tools: list[AgentToolResponse]) -> None:
|
|
180
|
+
"""Pre-populate with existing tool configurations.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
tools: List of existing tool configurations to load
|
|
184
|
+
"""
|
|
185
|
+
# Sort by tool_order
|
|
186
|
+
sorted_tools = sorted(tools, key=lambda t: t.tool_order)
|
|
187
|
+
|
|
188
|
+
for tool in sorted_tools:
|
|
189
|
+
self._add_tool_editor_with_data(tool)
|
|
190
|
+
|
|
191
|
+
def _add_tool_editor_with_data(self, tool: AgentToolResponse) -> None:
|
|
192
|
+
"""Add a tool editor and populate it with existing data."""
|
|
193
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
194
|
+
editor = AgentToolEditor(
|
|
195
|
+
client=self._client,
|
|
196
|
+
tool_order=self._editor_count,
|
|
197
|
+
id=f"tool-editor-{self._editor_count}",
|
|
198
|
+
)
|
|
199
|
+
tools_list.mount(editor)
|
|
200
|
+
self._editor_count += 1
|
|
201
|
+
self._update_empty_message()
|
|
202
|
+
|
|
203
|
+
# Populate after mounting
|
|
204
|
+
editor.populate_from_response(tool)
|
|
205
|
+
|
|
206
|
+
def clear(self) -> None:
|
|
207
|
+
"""Remove all tool editors."""
|
|
208
|
+
tools_list = self.query_one("#tools-list", VerticalScroll)
|
|
209
|
+
for editor in list(tools_list.query(AgentToolEditor)):
|
|
210
|
+
editor.remove()
|
|
211
|
+
self._editor_count = 0
|
|
212
|
+
self._update_empty_message()
|