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,68 @@
|
|
|
1
|
+
"""Presenter for agent update output."""
|
|
2
|
+
|
|
3
|
+
from cli.commands.agents.update.fields import (
|
|
4
|
+
format_generation_params,
|
|
5
|
+
format_models,
|
|
6
|
+
format_tags,
|
|
7
|
+
format_tools,
|
|
8
|
+
)
|
|
9
|
+
from cli.infrastructure.formatting.fields import (
|
|
10
|
+
format_datetime,
|
|
11
|
+
format_optional,
|
|
12
|
+
format_uuid,
|
|
13
|
+
)
|
|
14
|
+
from cli.infrastructure.output import OutputService
|
|
15
|
+
from cli.infrastructure.renderers.entity_renderer import FieldConfig
|
|
16
|
+
from alloy_runtime_types.dtos.agents import UpdateAgentResponse
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def present_agent_update_success(response: UpdateAgentResponse) -> None:
|
|
20
|
+
"""Present successful agent update.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
response: Agent update response from server
|
|
24
|
+
"""
|
|
25
|
+
output = OutputService.get()
|
|
26
|
+
output.success("Agent updated successfully")
|
|
27
|
+
|
|
28
|
+
fields = [
|
|
29
|
+
FieldConfig("id", "ID", lambda v: format_uuid(v, short=False)),
|
|
30
|
+
FieldConfig("name", "Name"),
|
|
31
|
+
FieldConfig("description", "Description", format_optional),
|
|
32
|
+
FieldConfig("models", "Models", lambda _: format_models(response)),
|
|
33
|
+
FieldConfig("tools", "Tools", lambda _: format_tools(response)),
|
|
34
|
+
FieldConfig("tags", "Tags", lambda _: format_tags(response)),
|
|
35
|
+
FieldConfig(
|
|
36
|
+
"generation_params",
|
|
37
|
+
"Generation Params",
|
|
38
|
+
lambda _: format_generation_params(response),
|
|
39
|
+
),
|
|
40
|
+
FieldConfig(
|
|
41
|
+
"system_instruction_version_id",
|
|
42
|
+
"System Prompt ID",
|
|
43
|
+
lambda v: format_optional(v, lambda x: format_uuid(x, short=False)),
|
|
44
|
+
),
|
|
45
|
+
FieldConfig(
|
|
46
|
+
"input_schema_id",
|
|
47
|
+
"Input Schema ID",
|
|
48
|
+
lambda v: format_optional(v, lambda x: format_uuid(x, short=False)),
|
|
49
|
+
),
|
|
50
|
+
FieldConfig(
|
|
51
|
+
"output_schema_id",
|
|
52
|
+
"Output Schema ID",
|
|
53
|
+
lambda v: format_optional(v, lambda x: format_uuid(x, short=False)),
|
|
54
|
+
),
|
|
55
|
+
FieldConfig(
|
|
56
|
+
"organization_id",
|
|
57
|
+
"Organization ID",
|
|
58
|
+
lambda v: format_optional(v, lambda x: format_uuid(x, short=True)),
|
|
59
|
+
),
|
|
60
|
+
FieldConfig(
|
|
61
|
+
"user_id",
|
|
62
|
+
"User ID",
|
|
63
|
+
lambda v: format_optional(v, lambda x: format_uuid(x, short=True)),
|
|
64
|
+
),
|
|
65
|
+
FieldConfig("updated_at", "Updated At", format_datetime),
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
output.entity(response, f"Agent: {response.name}", fields)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Audio transcribe command implementation."""
|
|
2
|
+
|
|
3
|
+
import mimetypes
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from cli.commands.audio.transcribe.presenter import present_transcription
|
|
10
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
11
|
+
|
|
12
|
+
MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024 # 25 MB
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolve_audio_input(file: str) -> tuple[bytes, str, str]:
|
|
16
|
+
"""Validate and read audio input from a file path or stdin.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
file: File path to an audio file, or '-' for stdin.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Tuple of (file_bytes, filename, content_type).
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
typer.BadParameter: If the file is not found, not readable,
|
|
26
|
+
or exceeds the 25MB size limit.
|
|
27
|
+
"""
|
|
28
|
+
if file == "-":
|
|
29
|
+
return _read_stdin()
|
|
30
|
+
|
|
31
|
+
return _read_file(file)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _read_stdin() -> tuple[bytes, str, str]:
|
|
35
|
+
"""Read audio bytes from stdin.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Tuple of (file_bytes, filename, content_type).
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
typer.BadParameter: If stdin data exceeds size limit.
|
|
42
|
+
"""
|
|
43
|
+
file_bytes = sys.stdin.buffer.read()
|
|
44
|
+
if len(file_bytes) > MAX_FILE_SIZE_BYTES:
|
|
45
|
+
size_mb = len(file_bytes) / (1024 * 1024)
|
|
46
|
+
raise typer.BadParameter(
|
|
47
|
+
f"Stdin data ({size_mb:.1f} MB) exceeds the 25 MB upload limit."
|
|
48
|
+
)
|
|
49
|
+
return file_bytes, "audio.wav", "audio/wav"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _read_file(file: str) -> tuple[bytes, str, str]:
|
|
53
|
+
"""Read and validate an audio file from disk.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
file: Path to the audio file.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Tuple of (file_bytes, filename, content_type).
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
typer.BadParameter: If the file is not found, not a regular file,
|
|
63
|
+
or exceeds the 25MB size limit.
|
|
64
|
+
"""
|
|
65
|
+
path = Path(file).expanduser()
|
|
66
|
+
|
|
67
|
+
if not path.exists():
|
|
68
|
+
raise typer.BadParameter(f"File not found: {file}")
|
|
69
|
+
|
|
70
|
+
if not path.is_file():
|
|
71
|
+
raise typer.BadParameter(f"Not a file: {file}")
|
|
72
|
+
|
|
73
|
+
file_size = path.stat().st_size
|
|
74
|
+
if file_size > MAX_FILE_SIZE_BYTES:
|
|
75
|
+
size_mb = file_size / (1024 * 1024)
|
|
76
|
+
raise typer.BadParameter(
|
|
77
|
+
f"File ({size_mb:.1f} MB) exceeds the 25 MB upload limit."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
file_bytes = path.read_bytes()
|
|
81
|
+
filename = path.name
|
|
82
|
+
content_type = _detect_content_type(path)
|
|
83
|
+
|
|
84
|
+
return file_bytes, filename, content_type
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _detect_content_type(path: Path) -> str:
|
|
88
|
+
"""Detect the MIME content type from the file extension.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
path: Path to the file.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
MIME type string. Defaults to 'audio/wav' if detection fails.
|
|
95
|
+
"""
|
|
96
|
+
guessed, _ = mimetypes.guess_type(str(path))
|
|
97
|
+
if guessed and guessed.startswith("audio/"):
|
|
98
|
+
return guessed
|
|
99
|
+
return "audio/wav"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def audio_transcribe_command(
|
|
103
|
+
file: str = typer.Argument(
|
|
104
|
+
...,
|
|
105
|
+
help="Path to audio file, or '-' for stdin.",
|
|
106
|
+
),
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Transcribe audio to text.
|
|
109
|
+
|
|
110
|
+
Accepts a local audio file or piped stdin. The file must be under 25 MB.
|
|
111
|
+
Content type is auto-detected from the file extension.
|
|
112
|
+
|
|
113
|
+
Examples:
|
|
114
|
+
ai audio transcribe recording.wav
|
|
115
|
+
ai audio transcribe ~/voice-memo.mp3
|
|
116
|
+
cat audio.wav | ai audio transcribe -
|
|
117
|
+
"""
|
|
118
|
+
file_bytes, filename, content_type = resolve_audio_input(file)
|
|
119
|
+
_execute_transcribe(
|
|
120
|
+
file_bytes=file_bytes, filename=filename, content_type=content_type
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@async_command
|
|
125
|
+
async def _execute_transcribe(
|
|
126
|
+
file_bytes: bytes,
|
|
127
|
+
filename: str,
|
|
128
|
+
content_type: str,
|
|
129
|
+
) -> None:
|
|
130
|
+
"""Execute the transcribe operation.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
file_bytes: Raw audio bytes to upload.
|
|
134
|
+
filename: Name of the audio file.
|
|
135
|
+
content_type: MIME content type of the audio.
|
|
136
|
+
"""
|
|
137
|
+
async with authenticated_client() as (_config, client):
|
|
138
|
+
response = await client.transcribe_audio(
|
|
139
|
+
file_bytes,
|
|
140
|
+
filename=filename,
|
|
141
|
+
content_type=content_type,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
present_transcription(response)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Presenter for audio transcribe command output."""
|
|
2
|
+
|
|
3
|
+
from alloy_runtime_types.dtos.audio import AudioTranscriptResponse
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def present_transcription(response: AudioTranscriptResponse) -> None:
|
|
7
|
+
"""Print transcribed text to stdout.
|
|
8
|
+
|
|
9
|
+
Output is piping-friendly: only the transcribed text goes to stdout
|
|
10
|
+
with no decoration or metadata.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
response: Transcription response from the server.
|
|
14
|
+
"""
|
|
15
|
+
print(response.text)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Login command implementation."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from cli.infrastructure.auth_storage import save_credentials
|
|
6
|
+
from cli.infrastructure.command import async_command
|
|
7
|
+
from cli.infrastructure.config import get_api_url
|
|
8
|
+
from cli.infrastructure.console import Confirm, Prompt, get_console
|
|
9
|
+
from cli.infrastructure.output import print_info, print_success
|
|
10
|
+
from cli.infrastructure.provider_setup import prompt_provider_credentials
|
|
11
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
12
|
+
from alloy_runtime_types.dtos.auth import LoginRequest
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def login_command(
|
|
16
|
+
email: str | None = typer.Option(None, "-e", "--email", help="Email address"),
|
|
17
|
+
password: str | None = typer.Option(
|
|
18
|
+
None, "--password", help="Password (avoid: exposes in shell history)"
|
|
19
|
+
),
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Login and save API key.
|
|
22
|
+
|
|
23
|
+
First-time users will be prompted to set up provider credentials.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
|
|
27
|
+
alloy login
|
|
28
|
+
alloy login -e user@example.com
|
|
29
|
+
"""
|
|
30
|
+
_execute_login(email, password)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@async_command
|
|
34
|
+
async def _execute_login(
|
|
35
|
+
email: str | None,
|
|
36
|
+
password: str | None,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Execute the login operation.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
email: Optional email (will prompt if not provided)
|
|
42
|
+
password: Optional password (will prompt if not provided)
|
|
43
|
+
"""
|
|
44
|
+
console = get_console()
|
|
45
|
+
api_url = get_api_url()
|
|
46
|
+
|
|
47
|
+
# Prompt for credentials if not provided
|
|
48
|
+
if not email:
|
|
49
|
+
email = Prompt.ask("[cyan]Email[/cyan]")
|
|
50
|
+
|
|
51
|
+
if not password:
|
|
52
|
+
password = Prompt.ask("[cyan]Password[/cyan]", password=True)
|
|
53
|
+
|
|
54
|
+
console.print("\n[blue]Authenticating...[/blue]")
|
|
55
|
+
|
|
56
|
+
# Create unauthenticated client
|
|
57
|
+
async with ApiClient(base_url=api_url, api_key="") as client:
|
|
58
|
+
response = await client.login(LoginRequest(email=email, password=password))
|
|
59
|
+
|
|
60
|
+
# Save credentials
|
|
61
|
+
save_credentials(api_url, response.api_key)
|
|
62
|
+
|
|
63
|
+
print_success(f"Logged in as {response.name} ({response.email})")
|
|
64
|
+
print_info("API key saved to ~/.alloy-runtime/config")
|
|
65
|
+
print_info(f"Organization: {response.organization_id}")
|
|
66
|
+
|
|
67
|
+
# Prompt for provider credentials if new user
|
|
68
|
+
if response.is_new_user:
|
|
69
|
+
console.print("\n[yellow]Welcome! This is your first login.[/yellow]")
|
|
70
|
+
if Confirm.ask(
|
|
71
|
+
"Would you like to set up AI provider credentials now?", default=True
|
|
72
|
+
):
|
|
73
|
+
await prompt_provider_credentials(api_url, response.api_key)
|
|
74
|
+
else:
|
|
75
|
+
console.print(
|
|
76
|
+
"\n[dim]You can set up provider credentials later with:[/dim]"
|
|
77
|
+
)
|
|
78
|
+
console.print(
|
|
79
|
+
"[dim] alloy credentials update <credential-id> --value <api-key>[/dim]"
|
|
80
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Signup command implementation."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from cli.infrastructure.auth_storage import save_credentials
|
|
6
|
+
from cli.infrastructure.command import async_command
|
|
7
|
+
from cli.infrastructure.config import get_api_url
|
|
8
|
+
from cli.infrastructure.console import Confirm, Prompt, get_console
|
|
9
|
+
from cli.infrastructure.output import print_info, print_success
|
|
10
|
+
from cli.infrastructure.provider_setup import prompt_provider_credentials
|
|
11
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
12
|
+
from alloy_runtime_types.dtos.auth import SignupRequest
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def signup_command(
|
|
16
|
+
email: str | None = typer.Option(None, "-e", "--email", help="Email address"),
|
|
17
|
+
password: str | None = typer.Option(
|
|
18
|
+
None, "--password", help="Password (avoid: exposes in shell history)"
|
|
19
|
+
),
|
|
20
|
+
name: str | None = typer.Option(None, "-n", "--name", help="Display name"),
|
|
21
|
+
org_name: str | None = typer.Option(
|
|
22
|
+
None,
|
|
23
|
+
"--org",
|
|
24
|
+
help="Organization name",
|
|
25
|
+
),
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Create a new Alloy Runtime account.
|
|
28
|
+
|
|
29
|
+
You'll be prompted to set up provider credentials after signup.
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
|
|
33
|
+
ai signup
|
|
34
|
+
ai signup -e user@example.com -n "John Doe" --org "My Company"
|
|
35
|
+
"""
|
|
36
|
+
_execute_signup(email, password, name, org_name)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@async_command
|
|
40
|
+
async def _execute_signup(
|
|
41
|
+
email: str | None,
|
|
42
|
+
password: str | None,
|
|
43
|
+
name: str | None,
|
|
44
|
+
org_name: str | None,
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Execute the signup operation.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
email: Optional email (will prompt if not provided)
|
|
50
|
+
password: Optional password (will prompt if not provided)
|
|
51
|
+
name: Optional name (will prompt if not provided)
|
|
52
|
+
org_name: Optional organization name
|
|
53
|
+
"""
|
|
54
|
+
console = get_console()
|
|
55
|
+
api_url = get_api_url()
|
|
56
|
+
|
|
57
|
+
# Prompt for required fields if not provided
|
|
58
|
+
if not email:
|
|
59
|
+
email = Prompt.ask("[cyan]Email address[/cyan]")
|
|
60
|
+
|
|
61
|
+
if not name:
|
|
62
|
+
name = Prompt.ask("[cyan]Your name[/cyan]")
|
|
63
|
+
|
|
64
|
+
if not password:
|
|
65
|
+
while True:
|
|
66
|
+
password = Prompt.ask("[cyan]Password[/cyan] (min 8 chars)", password=True)
|
|
67
|
+
confirm = Prompt.ask("[cyan]Confirm password[/cyan]", password=True)
|
|
68
|
+
|
|
69
|
+
if password != confirm:
|
|
70
|
+
console.print("[red]Passwords do not match. Please try again.[/red]\n")
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
if password and len(password) < 8:
|
|
74
|
+
console.print("[red]Password must be at least 8 characters.[/red]\n")
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
break
|
|
78
|
+
|
|
79
|
+
console.print("\n[blue]Creating your account...[/blue]")
|
|
80
|
+
|
|
81
|
+
# Create unauthenticated client
|
|
82
|
+
async with ApiClient(base_url=api_url, api_key="") as client:
|
|
83
|
+
response = await client.signup(
|
|
84
|
+
SignupRequest(
|
|
85
|
+
email=email,
|
|
86
|
+
password=password,
|
|
87
|
+
name=name,
|
|
88
|
+
organization_name=org_name,
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Save credentials
|
|
93
|
+
save_credentials(api_url, response.api_key)
|
|
94
|
+
|
|
95
|
+
console.print()
|
|
96
|
+
print_success(f"Account created for {response.name}")
|
|
97
|
+
print_info(f"Email: {response.email}")
|
|
98
|
+
print_info(f"Organization ID: {response.organization_id}")
|
|
99
|
+
print_info("API key saved to ~/.alloy-runtime/config")
|
|
100
|
+
|
|
101
|
+
# Prompt for provider setup
|
|
102
|
+
console.print(
|
|
103
|
+
"\n[bold yellow]Let's set up your AI provider credentials[/bold yellow]"
|
|
104
|
+
)
|
|
105
|
+
console.print(
|
|
106
|
+
"[dim]You'll need API keys from providers like OpenAI, Anthropic, or Google.[/dim]\n"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if Confirm.ask("Set up provider credentials now?", default=True):
|
|
110
|
+
await prompt_provider_credentials(api_url, response.api_key)
|
|
111
|
+
else:
|
|
112
|
+
console.print("\n[dim]You can add provider credentials later with:[/dim]")
|
|
113
|
+
console.print(
|
|
114
|
+
"[dim] ai credentials update <credential-id> --value <api-key>[/dim]"
|
|
115
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty per project convention - import directly from submodules
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty per project convention - import directly from submodules
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty per project convention - import directly from submodules
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Billing project costs by agent command implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from cli.commands.billing.costs.by_agent.presenter import present_billing_costs_by_agent
|
|
9
|
+
from cli.commands.flag_utils import validate_uuid
|
|
10
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def billing_costs_by_agent_command(
|
|
14
|
+
project_id: str = typer.Argument(
|
|
15
|
+
...,
|
|
16
|
+
help="Billing project UUID",
|
|
17
|
+
),
|
|
18
|
+
start_date: Optional[str] = typer.Option(
|
|
19
|
+
None,
|
|
20
|
+
"--from",
|
|
21
|
+
help="Start date (ISO 8601, defaults to 30 days ago)",
|
|
22
|
+
),
|
|
23
|
+
end_date: Optional[str] = typer.Option(
|
|
24
|
+
None,
|
|
25
|
+
"--to",
|
|
26
|
+
help="End date (ISO 8601, defaults to now)",
|
|
27
|
+
),
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Get cost breakdown by agent for a billing project.
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
ai billing costs by-agent 123e4567-89ab...
|
|
33
|
+
ai billing costs by-agent 123e4567-89ab... --from 2026-01-01 --to 2026-01-31
|
|
34
|
+
"""
|
|
35
|
+
project_uuid = validate_uuid(project_id, "billing project")
|
|
36
|
+
_execute_costs_by_agent(
|
|
37
|
+
project_id=project_uuid,
|
|
38
|
+
start_date=start_date,
|
|
39
|
+
end_date=end_date,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@async_command
|
|
44
|
+
async def _execute_costs_by_agent(
|
|
45
|
+
project_id: UUID,
|
|
46
|
+
start_date: Optional[str],
|
|
47
|
+
end_date: Optional[str],
|
|
48
|
+
) -> None:
|
|
49
|
+
"""Execute get billing project costs by agent operation."""
|
|
50
|
+
async with authenticated_client() as (_config, client):
|
|
51
|
+
response = await client.get_billing_project_costs_by_agent(
|
|
52
|
+
project_id,
|
|
53
|
+
start_date=start_date,
|
|
54
|
+
end_date=end_date,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
present_billing_costs_by_agent(response)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Presenter for billing project costs by agent command output."""
|
|
2
|
+
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
|
|
5
|
+
from alloy_runtime_types.dtos.billing import ProjectCostByAgent
|
|
6
|
+
|
|
7
|
+
from cli.infrastructure.output import OutputService
|
|
8
|
+
from cli.infrastructure.renderers.list_renderer import ColumnConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _format_cost(cost: Decimal | None) -> str:
|
|
12
|
+
"""Format cost for display."""
|
|
13
|
+
if cost is None:
|
|
14
|
+
return "-"
|
|
15
|
+
return f"${cost:.4f}"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def present_billing_costs_by_agent(entries: list[ProjectCostByAgent]) -> None:
|
|
19
|
+
"""Present billing project cost breakdown by agent."""
|
|
20
|
+
output = OutputService.get()
|
|
21
|
+
|
|
22
|
+
if not entries:
|
|
23
|
+
output.info("No cost data by agent found")
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
columns = [
|
|
27
|
+
ColumnConfig(
|
|
28
|
+
source_field="agent_name",
|
|
29
|
+
header_label="Agent",
|
|
30
|
+
compact_line=1,
|
|
31
|
+
compact_style="green",
|
|
32
|
+
),
|
|
33
|
+
ColumnConfig(
|
|
34
|
+
source_field="agent_id",
|
|
35
|
+
header_label="Agent ID",
|
|
36
|
+
formatter=lambda x: str(x) if x else "(transient)",
|
|
37
|
+
compact_line=2,
|
|
38
|
+
compact_style="dim",
|
|
39
|
+
),
|
|
40
|
+
ColumnConfig(
|
|
41
|
+
source_field="execution_count",
|
|
42
|
+
header_label="Executions",
|
|
43
|
+
formatter=str,
|
|
44
|
+
compact_line=1,
|
|
45
|
+
compact_style="white",
|
|
46
|
+
),
|
|
47
|
+
ColumnConfig(
|
|
48
|
+
source_field="total_tokens",
|
|
49
|
+
header_label="Total Tokens",
|
|
50
|
+
formatter=lambda x: f"{x:,}",
|
|
51
|
+
compact_line=2,
|
|
52
|
+
compact_style="dim",
|
|
53
|
+
),
|
|
54
|
+
ColumnConfig(
|
|
55
|
+
source_field="llm_cost_usd",
|
|
56
|
+
header_label="LLM Cost",
|
|
57
|
+
formatter=_format_cost,
|
|
58
|
+
compact_line=2,
|
|
59
|
+
compact_style="dim",
|
|
60
|
+
),
|
|
61
|
+
ColumnConfig(
|
|
62
|
+
source_field="rag_cost_usd",
|
|
63
|
+
header_label="RAG Cost",
|
|
64
|
+
formatter=_format_cost,
|
|
65
|
+
compact_line=2,
|
|
66
|
+
compact_style="dim",
|
|
67
|
+
),
|
|
68
|
+
ColumnConfig(
|
|
69
|
+
source_field="total_cost_usd",
|
|
70
|
+
header_label="Total Cost",
|
|
71
|
+
formatter=_format_cost,
|
|
72
|
+
compact_line=1,
|
|
73
|
+
compact_style="green bold",
|
|
74
|
+
),
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
output.table(
|
|
78
|
+
items=entries, # type: ignore[arg-type]
|
|
79
|
+
title=f"Costs by Agent ({len(entries)} agents)",
|
|
80
|
+
columns=columns,
|
|
81
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty per project convention - import directly from submodules
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Billing project costs by model command implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from cli.commands.billing.costs.by_model.presenter import present_billing_costs_by_model
|
|
9
|
+
from cli.commands.flag_utils import validate_uuid
|
|
10
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def billing_costs_by_model_command(
|
|
14
|
+
project_id: str = typer.Argument(
|
|
15
|
+
...,
|
|
16
|
+
help="Billing project UUID",
|
|
17
|
+
),
|
|
18
|
+
start_date: Optional[str] = typer.Option(
|
|
19
|
+
None,
|
|
20
|
+
"--from",
|
|
21
|
+
help="Start date (ISO 8601, defaults to 30 days ago)",
|
|
22
|
+
),
|
|
23
|
+
end_date: Optional[str] = typer.Option(
|
|
24
|
+
None,
|
|
25
|
+
"--to",
|
|
26
|
+
help="End date (ISO 8601, defaults to now)",
|
|
27
|
+
),
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Get cost breakdown by model for a billing project.
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
ai billing costs by-model 123e4567-89ab...
|
|
33
|
+
ai billing costs by-model 123e4567-89ab... --from 2026-01-01 --to 2026-01-31
|
|
34
|
+
"""
|
|
35
|
+
project_uuid = validate_uuid(project_id, "billing project")
|
|
36
|
+
_execute_costs_by_model(
|
|
37
|
+
project_id=project_uuid,
|
|
38
|
+
start_date=start_date,
|
|
39
|
+
end_date=end_date,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@async_command
|
|
44
|
+
async def _execute_costs_by_model(
|
|
45
|
+
project_id: UUID,
|
|
46
|
+
start_date: Optional[str],
|
|
47
|
+
end_date: Optional[str],
|
|
48
|
+
) -> None:
|
|
49
|
+
"""Execute get billing project costs by model operation."""
|
|
50
|
+
async with authenticated_client() as (_config, client):
|
|
51
|
+
response = await client.get_billing_project_costs_by_model(
|
|
52
|
+
project_id,
|
|
53
|
+
start_date=start_date,
|
|
54
|
+
end_date=end_date,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
present_billing_costs_by_model(response)
|