meshagent-cli 0.52.0__tar.gz → 0.52.3__tar.gz
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.
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/PKG-INFO +18 -18
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/cli.py +7 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/config.py +44 -16
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/config_test.py +47 -0
- meshagent_cli-0.52.3/meshagent/cli/oauth_clients.py +120 -0
- meshagent_cli-0.52.3/meshagent/cli/oauth_clients_test.py +89 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/process.py +1 -1
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/process_test.py +1 -1
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/projects.py +80 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/projects_test.py +169 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/sqlite.py +119 -0
- meshagent_cli-0.52.3/meshagent/cli/sqlite_recovery.py +373 -0
- meshagent_cli-0.52.3/meshagent/cli/sqlite_recovery_test.py +1004 -0
- meshagent_cli-0.52.3/meshagent/cli/sqlite_test.py +91 -0
- meshagent_cli-0.52.3/meshagent/cli/sqlite_transfer_test.py +105 -0
- meshagent_cli-0.52.3/meshagent/cli/version.py +1 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent_cli.egg-info/PKG-INFO +18 -18
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent_cli.egg-info/SOURCES.txt +5 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent_cli.egg-info/requires.txt +17 -17
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/pyproject.toml +17 -17
- meshagent_cli-0.52.0/meshagent/cli/sqlite_test.py +0 -68
- meshagent_cli-0.52.0/meshagent/cli/version.py +0 -1
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/LICENSE +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/README.md +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/__init__.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/_filedrop.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/agent.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/agent_cli_options_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/agent_package_cli.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/agent_package_cli_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/agents.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/agents_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/ask.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/ask_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/async_typer.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/async_typer_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/auth.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/auth_async.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/auth_async_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/auth_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/call.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/chatbot.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/cli_mcp.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/cli_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/common_options.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/containers.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/containers_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/__init__.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/backend-agent/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/contact-form/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/slack-channel/channel.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/slack-channel/scripts/configure-slack.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/slack-channel/scripts/setup-slack-dev-route.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/slack-channel/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/task-queue-dashboard/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/telegram-channel/channel.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/telegram-channel/scripts/configure-telegram.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/telegram-channel/scripts/create-bot-token.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/telegram-channel/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/twilio-channel/channel.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/twilio-channel/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/webserver/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/whatsapp-channel/channel.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_project_templates/python/whatsapp-channel/server.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/create_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/custom_domains.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/custom_domains_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/dataset.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/dataset_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/developer.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/developer_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/doctor.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/doctor_dockerfiles/__init__.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/doctor_templates/__init__.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/doctor_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/feeds.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/feeds_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/helper.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/helper_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/helpers.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/host.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/iam.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/iam_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/image.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/image_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/launch.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/launch_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/llm.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/llm_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/local_settings.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/local_settings_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/mailbot.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/mailbot_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/mailboxes.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/mailboxes_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/meeting_transcriber.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/memory.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/memory_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/meshagent_images.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/meshagent_images_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/messaging.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/messaging_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/mounts.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/multi.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/oci_archive.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/oci_archive_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/participant_token.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/port.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/port_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/preamble_rules.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/preamble_rules_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/process_live_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/queue.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/queue_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/registry.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/registry_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/room.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/room_connect.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/room_connect_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/room_services.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/room_services_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/rooms.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/rooms_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/root_commands.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/root_commands_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/routes.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/routes_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/sample_channel_http_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/sample_channel_live_e2e_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/scheduled_tasks.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/scheduled_tasks_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/secrets.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/secrets_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/service_accounts.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/service_accounts_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/services.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/services_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/sessions.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/sessions_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/storage.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/storage_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/subscriptions.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/sync.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/sync_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/task_runner.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/task_runner_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/testing.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/thread_inspect.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/thread_inspect_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/thread_sidebar.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tool_call_summary.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tool_call_summary_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tool_integrations.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tool_integrations_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/__init__.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/auth_switch.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/auth_switch_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/create.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/deploy_room.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/deploy_room_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/project_activate.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/project_activate_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/setup.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/setup_splash_frames.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/tui/setup_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/version_check.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/version_check_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/voicebot.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/volumes.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/volumes_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/webserver.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/webserver_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/worker.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent/cli/worker_test.py +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent_cli.egg-info/dependency_links.txt +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent_cli.egg-info/entry_points.txt +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/meshagent_cli.egg-info/top_level.txt +0 -0
- {meshagent_cli-0.52.0 → meshagent_cli-0.52.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshagent-cli
|
|
3
|
-
Version: 0.52.
|
|
3
|
+
Version: 0.52.3
|
|
4
4
|
Summary: CLI for Meshagent
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Documentation, https://docs.meshagent.com
|
|
@@ -17,13 +17,13 @@ Requires-Dist: opentelemetry-exporter-otlp-proto-http~=1.33
|
|
|
17
17
|
Requires-Dist: art~=6.5
|
|
18
18
|
Requires-Dist: pyyaml~=6.0.2
|
|
19
19
|
Requires-Dist: pydantic-yaml~=1.5
|
|
20
|
-
Requires-Dist: pyarrow~=
|
|
20
|
+
Requires-Dist: pyarrow~=22.0.0
|
|
21
21
|
Requires-Dist: openpyxl~=3.1
|
|
22
22
|
Requires-Dist: xlsxwriter~=3.2
|
|
23
23
|
Requires-Dist: pathspec<2,>=1.0.3
|
|
24
24
|
Requires-Dist: zstandard~=0.25.0
|
|
25
|
-
Requires-Dist: meshagent-llm-proxy==0.52.
|
|
26
|
-
Requires-Dist: meshagent-codex==0.52.
|
|
25
|
+
Requires-Dist: meshagent-llm-proxy==0.52.3
|
|
26
|
+
Requires-Dist: meshagent-codex==0.52.3
|
|
27
27
|
Requires-Dist: rich~=14.3.0
|
|
28
28
|
Requires-Dist: sounddevice~=0.5
|
|
29
29
|
Requires-Dist: textual<9.0,>=8.2.3
|
|
@@ -32,23 +32,23 @@ Requires-Dist: prompt-toolkit~=3.0.52
|
|
|
32
32
|
Requires-Dist: ascii-magic~=2.3
|
|
33
33
|
Requires-Dist: pillow~=11.3.0
|
|
34
34
|
Provides-Extra: all
|
|
35
|
-
Requires-Dist: meshagent-agents[all]==0.52.
|
|
36
|
-
Requires-Dist: meshagent-api[all]==0.52.
|
|
37
|
-
Requires-Dist: meshagent-commoncrawl==0.52.
|
|
38
|
-
Requires-Dist: meshagent-scrapy==0.52.
|
|
39
|
-
Requires-Dist: meshagent-computers==0.52.
|
|
40
|
-
Requires-Dist: meshagent-openai==0.52.
|
|
41
|
-
Requires-Dist: meshagent-anthropic==0.52.
|
|
42
|
-
Requires-Dist: meshagent-otel==0.52.
|
|
43
|
-
Requires-Dist: meshagent-mcp==0.52.
|
|
44
|
-
Requires-Dist: meshagent-tools==0.52.
|
|
35
|
+
Requires-Dist: meshagent-agents[all]==0.52.3; extra == "all"
|
|
36
|
+
Requires-Dist: meshagent-api[all]==0.52.3; extra == "all"
|
|
37
|
+
Requires-Dist: meshagent-commoncrawl==0.52.3; extra == "all"
|
|
38
|
+
Requires-Dist: meshagent-scrapy==0.52.3; extra == "all"
|
|
39
|
+
Requires-Dist: meshagent-computers==0.52.3; extra == "all"
|
|
40
|
+
Requires-Dist: meshagent-openai==0.52.3; extra == "all"
|
|
41
|
+
Requires-Dist: meshagent-anthropic==0.52.3; extra == "all"
|
|
42
|
+
Requires-Dist: meshagent-otel==0.52.3; extra == "all"
|
|
43
|
+
Requires-Dist: meshagent-mcp==0.52.3; extra == "all"
|
|
44
|
+
Requires-Dist: meshagent-tools==0.52.3; extra == "all"
|
|
45
45
|
Requires-Dist: supabase-auth~=2.28.0; extra == "all"
|
|
46
46
|
Requires-Dist: prompt-toolkit~=3.0.52; extra == "all"
|
|
47
47
|
Provides-Extra: mcp-service
|
|
48
|
-
Requires-Dist: meshagent-agents[all]==0.52.
|
|
49
|
-
Requires-Dist: meshagent-api==0.52.
|
|
50
|
-
Requires-Dist: meshagent-mcp==0.52.
|
|
51
|
-
Requires-Dist: meshagent-tools==0.52.
|
|
48
|
+
Requires-Dist: meshagent-agents[all]==0.52.3; extra == "mcp-service"
|
|
49
|
+
Requires-Dist: meshagent-api==0.52.3; extra == "mcp-service"
|
|
50
|
+
Requires-Dist: meshagent-mcp==0.52.3; extra == "mcp-service"
|
|
51
|
+
Requires-Dist: meshagent-tools==0.52.3; extra == "mcp-service"
|
|
52
52
|
Requires-Dist: supabase-auth~=2.28.0; extra == "mcp-service"
|
|
53
53
|
Dynamic: license-file
|
|
54
54
|
|
|
@@ -386,6 +386,13 @@ SHELL_RENDERERS = {
|
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
|
|
389
|
+
app.add_lazy_command(
|
|
390
|
+
name="oauth-client",
|
|
391
|
+
module="meshagent.cli.oauth_clients",
|
|
392
|
+
help="Manage OAuth clients and login branding",
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
|
|
389
396
|
def main() -> None:
|
|
390
397
|
from meshagent.agents.channel_process import dispatch_main
|
|
391
398
|
|
|
@@ -8,19 +8,49 @@ from meshagent.api import RoomException
|
|
|
8
8
|
from meshagent.api.client import MeshagentDeploymentConfig
|
|
9
9
|
from meshagent.cli import async_typer
|
|
10
10
|
from meshagent.cli.helper import get_client
|
|
11
|
+
from meshagent.cli.local_settings import resolve_api_url
|
|
11
12
|
|
|
12
13
|
app = async_typer.AsyncTyper(help="Read MeshAgent deployment configuration")
|
|
13
14
|
|
|
15
|
+
SUPPORTED_CONFIG_PATHS = (
|
|
16
|
+
"version",
|
|
17
|
+
"openai.url",
|
|
18
|
+
"anthropic.url",
|
|
19
|
+
"grok.url",
|
|
20
|
+
"domains.studio",
|
|
21
|
+
"domains.accounts",
|
|
22
|
+
"domains.powerboards",
|
|
23
|
+
"domains.api",
|
|
24
|
+
"domains.mail",
|
|
25
|
+
"domains.pages",
|
|
26
|
+
"domains.registry",
|
|
27
|
+
)
|
|
28
|
+
|
|
14
29
|
|
|
15
30
|
@app.callback()
|
|
16
31
|
def _config_callback() -> None:
|
|
17
32
|
pass
|
|
18
33
|
|
|
19
34
|
|
|
20
|
-
def
|
|
35
|
+
def _llm_proxy_url(*, api_url: str, provider_path: str) -> str:
|
|
36
|
+
return f"{api_url.rstrip('/')}/{provider_path}"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _config_value(
|
|
40
|
+
config: MeshagentDeploymentConfig,
|
|
41
|
+
path: str,
|
|
42
|
+
*,
|
|
43
|
+
api_url: str,
|
|
44
|
+
) -> str | None:
|
|
21
45
|
match path:
|
|
22
46
|
case "version":
|
|
23
47
|
return config.version
|
|
48
|
+
case "openai.url":
|
|
49
|
+
return _llm_proxy_url(api_url=api_url, provider_path="openai/v1")
|
|
50
|
+
case "anthropic.url":
|
|
51
|
+
return _llm_proxy_url(api_url=api_url, provider_path="anthropic")
|
|
52
|
+
case "grok.url":
|
|
53
|
+
return _llm_proxy_url(api_url=api_url, provider_path="grok/v1")
|
|
24
54
|
case "domains.studio":
|
|
25
55
|
return config.domains.studio
|
|
26
56
|
case "domains.accounts":
|
|
@@ -36,20 +66,9 @@ def _config_value(config: MeshagentDeploymentConfig, path: str) -> str | None:
|
|
|
36
66
|
case "domains.registry":
|
|
37
67
|
return config.domains.registry
|
|
38
68
|
case _:
|
|
39
|
-
supported_paths = ", ".join(
|
|
40
|
-
[
|
|
41
|
-
"version",
|
|
42
|
-
"domains.studio",
|
|
43
|
-
"domains.accounts",
|
|
44
|
-
"domains.powerboards",
|
|
45
|
-
"domains.api",
|
|
46
|
-
"domains.mail",
|
|
47
|
-
"domains.pages",
|
|
48
|
-
"domains.registry",
|
|
49
|
-
]
|
|
50
|
-
)
|
|
51
69
|
raise typer.BadParameter(
|
|
52
|
-
|
|
70
|
+
"unsupported config path; choose one of: "
|
|
71
|
+
f"{', '.join(SUPPORTED_CONFIG_PATHS)}"
|
|
53
72
|
)
|
|
54
73
|
|
|
55
74
|
|
|
@@ -57,7 +76,12 @@ def _config_value(config: MeshagentDeploymentConfig, path: str) -> str | None:
|
|
|
57
76
|
async def config_get(
|
|
58
77
|
path: Annotated[
|
|
59
78
|
str,
|
|
60
|
-
typer.Argument(
|
|
79
|
+
typer.Argument(
|
|
80
|
+
help=(
|
|
81
|
+
"Config path to read. Supported paths: "
|
|
82
|
+
f"{', '.join(SUPPORTED_CONFIG_PATHS)}"
|
|
83
|
+
)
|
|
84
|
+
),
|
|
61
85
|
],
|
|
62
86
|
) -> None:
|
|
63
87
|
"""Print one deployment config value."""
|
|
@@ -70,7 +94,11 @@ async def config_get(
|
|
|
70
94
|
finally:
|
|
71
95
|
await client.close()
|
|
72
96
|
|
|
73
|
-
value = _config_value(
|
|
97
|
+
value = _config_value(
|
|
98
|
+
config,
|
|
99
|
+
path.strip(),
|
|
100
|
+
api_url=resolve_api_url(),
|
|
101
|
+
)
|
|
74
102
|
if value is None:
|
|
75
103
|
typer.echo(f"Config value is not set: {path.strip()}", err=True)
|
|
76
104
|
raise typer.Exit(1)
|
|
@@ -63,6 +63,53 @@ def test_config_get_version_prints_server_version(
|
|
|
63
63
|
assert fake_client.closed is True
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
@pytest.mark.parametrize(
|
|
67
|
+
("path", "expected"),
|
|
68
|
+
[
|
|
69
|
+
("openai.url", "https://api.meshagent.example/openai/v1"),
|
|
70
|
+
("anthropic.url", "https://api.meshagent.example/anthropic"),
|
|
71
|
+
("grok.url", "https://api.meshagent.example/grok/v1"),
|
|
72
|
+
],
|
|
73
|
+
)
|
|
74
|
+
def test_config_get_prints_llm_proxy_url_for_active_deployment(
|
|
75
|
+
path: str,
|
|
76
|
+
expected: str,
|
|
77
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
78
|
+
capsys: pytest.CaptureFixture[str],
|
|
79
|
+
) -> None:
|
|
80
|
+
fake_client = _FakeConfigClient(
|
|
81
|
+
MeshagentDeploymentConfig(domains=MeshagentDomains())
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
async def _fake_get_client() -> _FakeConfigClient:
|
|
85
|
+
return fake_client
|
|
86
|
+
|
|
87
|
+
monkeypatch.setattr(config, "get_client", _fake_get_client)
|
|
88
|
+
monkeypatch.setattr(
|
|
89
|
+
config,
|
|
90
|
+
"resolve_api_url",
|
|
91
|
+
lambda: "https://api.meshagent.example/",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
cli.app(["config", "get", path])
|
|
95
|
+
|
|
96
|
+
captured = capsys.readouterr()
|
|
97
|
+
assert captured.out == f"{expected}\n"
|
|
98
|
+
assert captured.err == ""
|
|
99
|
+
assert fake_client.closed is True
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_config_get_help_lists_supported_paths(
|
|
103
|
+
capsys: pytest.CaptureFixture[str],
|
|
104
|
+
) -> None:
|
|
105
|
+
cli.app(["config", "get", "--help"])
|
|
106
|
+
|
|
107
|
+
captured = capsys.readouterr()
|
|
108
|
+
for path in config.SUPPORTED_CONFIG_PATHS:
|
|
109
|
+
assert path in captured.out
|
|
110
|
+
assert captured.err == ""
|
|
111
|
+
|
|
112
|
+
|
|
66
113
|
def test_config_get_rejects_unknown_path(
|
|
67
114
|
monkeypatch: pytest.MonkeyPatch,
|
|
68
115
|
capsys: pytest.CaptureFixture[str],
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from meshagent.api.oauth_branding import OAuthClientBranding
|
|
6
|
+
from meshagent.cli import async_typer
|
|
7
|
+
from meshagent.cli.common_options import ProjectIdOption
|
|
8
|
+
from meshagent.cli.helper import get_client, resolve_project_id
|
|
9
|
+
from pydantic import ValidationError
|
|
10
|
+
from rich import print_json
|
|
11
|
+
|
|
12
|
+
app = async_typer.AsyncTyper(help="Manage OAuth clients and login branding")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Theme(str, Enum):
|
|
16
|
+
light = "light"
|
|
17
|
+
dark = "dark"
|
|
18
|
+
auto = "auto"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def branding_metadata(
|
|
22
|
+
existing: dict[str, str],
|
|
23
|
+
*,
|
|
24
|
+
name: str | None,
|
|
25
|
+
logo_url: str | None,
|
|
26
|
+
theme: Theme | None,
|
|
27
|
+
clear_logo: bool = False,
|
|
28
|
+
) -> dict[str, str]:
|
|
29
|
+
if clear_logo and logo_url is not None:
|
|
30
|
+
raise typer.BadParameter("Use either --logo-url or --clear-logo")
|
|
31
|
+
metadata = dict(existing)
|
|
32
|
+
if name is not None:
|
|
33
|
+
metadata["name"] = name
|
|
34
|
+
if clear_logo:
|
|
35
|
+
metadata.pop("logo_url", None)
|
|
36
|
+
elif logo_url is not None:
|
|
37
|
+
metadata["logo_url"] = logo_url
|
|
38
|
+
if theme is not None:
|
|
39
|
+
metadata["theme"] = theme.value
|
|
40
|
+
try:
|
|
41
|
+
OAuthClientBranding.model_validate(metadata)
|
|
42
|
+
except ValidationError as exc:
|
|
43
|
+
raise typer.BadParameter("Logo URL must be an absolute HTTP(S) URL") from exc
|
|
44
|
+
return metadata
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@app.command("create")
|
|
48
|
+
async def create_client(
|
|
49
|
+
name: Annotated[str, typer.Option(help="Application name shown at login")],
|
|
50
|
+
redirect_uri: Annotated[
|
|
51
|
+
list[str], typer.Option(help="Allowed callback URL; repeat for multiple URLs")
|
|
52
|
+
],
|
|
53
|
+
scope: Annotated[str, typer.Option(help="OAuth scopes")],
|
|
54
|
+
project_id: ProjectIdOption,
|
|
55
|
+
logo_url: Annotated[
|
|
56
|
+
str | None, typer.Option(help="Optional HTTP(S) login logo URL")
|
|
57
|
+
] = None,
|
|
58
|
+
theme: Annotated[Theme, typer.Option(help="Login appearance")] = Theme.auto,
|
|
59
|
+
):
|
|
60
|
+
"""Create an authorization-code client. The output includes its new secret."""
|
|
61
|
+
metadata = branding_metadata({}, name=name, logo_url=logo_url, theme=theme)
|
|
62
|
+
project_id = await resolve_project_id(project_id)
|
|
63
|
+
async with await get_client() as client:
|
|
64
|
+
result = await client.create_oauth_client(
|
|
65
|
+
project_id=project_id,
|
|
66
|
+
grant_types=["authorization_code", "refresh_token"],
|
|
67
|
+
response_types=["code"],
|
|
68
|
+
redirect_uris=redirect_uri,
|
|
69
|
+
scope=scope,
|
|
70
|
+
metadata=metadata,
|
|
71
|
+
)
|
|
72
|
+
print_json(result.model_dump_json())
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@app.command("update")
|
|
76
|
+
async def update_client(
|
|
77
|
+
client_id: Annotated[str, typer.Argument(help="OAuth client ID")],
|
|
78
|
+
project_id: ProjectIdOption,
|
|
79
|
+
name: Annotated[
|
|
80
|
+
str | None, typer.Option(help="Application name shown at login")
|
|
81
|
+
] = None,
|
|
82
|
+
logo_url: Annotated[str | None, typer.Option(help="HTTP(S) login logo URL")] = None,
|
|
83
|
+
theme: Annotated[
|
|
84
|
+
Theme | None, typer.Option(help="Login appearance: light, dark, or auto")
|
|
85
|
+
] = None,
|
|
86
|
+
clear_logo: Annotated[
|
|
87
|
+
bool, typer.Option(help="Restore the default MeshAgent logo")
|
|
88
|
+
] = False,
|
|
89
|
+
):
|
|
90
|
+
"""Update login branding, preserving other client settings and metadata."""
|
|
91
|
+
project_id = await resolve_project_id(project_id)
|
|
92
|
+
async with await get_client() as client:
|
|
93
|
+
existing = await client.get_oauth_client(
|
|
94
|
+
project_id=project_id, client_id=client_id
|
|
95
|
+
)
|
|
96
|
+
metadata = branding_metadata(
|
|
97
|
+
existing.metadata,
|
|
98
|
+
name=name,
|
|
99
|
+
logo_url=logo_url,
|
|
100
|
+
theme=theme,
|
|
101
|
+
clear_logo=clear_logo,
|
|
102
|
+
)
|
|
103
|
+
result = await client.update_oauth_client(
|
|
104
|
+
project_id=project_id, client_id=client_id, metadata=metadata
|
|
105
|
+
)
|
|
106
|
+
print_json(data=result)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@app.command("get")
|
|
110
|
+
async def get_client_config(
|
|
111
|
+
client_id: Annotated[str, typer.Argument(help="OAuth client ID")],
|
|
112
|
+
project_id: ProjectIdOption,
|
|
113
|
+
):
|
|
114
|
+
"""Show an OAuth client's configuration and branding."""
|
|
115
|
+
project_id = await resolve_project_id(project_id)
|
|
116
|
+
async with await get_client() as client:
|
|
117
|
+
result = await client.get_oauth_client(
|
|
118
|
+
project_id=project_id, client_id=client_id
|
|
119
|
+
)
|
|
120
|
+
print_json(result.model_dump_json())
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import typer
|
|
3
|
+
from meshagent.cli.oauth_clients import Theme, app, branding_metadata
|
|
4
|
+
from meshagent.cli.testing import CliRunner
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_branding_update_preserves_other_metadata():
|
|
8
|
+
assert branding_metadata(
|
|
9
|
+
{"name": "App", "custom": "keep", "logo_url": "https://old.example/logo"},
|
|
10
|
+
name=None,
|
|
11
|
+
logo_url=None,
|
|
12
|
+
theme=Theme.dark,
|
|
13
|
+
) == {
|
|
14
|
+
"name": "App",
|
|
15
|
+
"custom": "keep",
|
|
16
|
+
"logo_url": "https://old.example/logo",
|
|
17
|
+
"theme": "dark",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_clear_logo_restores_default_without_removing_name():
|
|
22
|
+
assert branding_metadata(
|
|
23
|
+
{"name": "App", "logo_url": "https://example.com/logo"},
|
|
24
|
+
name=None,
|
|
25
|
+
logo_url=None,
|
|
26
|
+
theme=None,
|
|
27
|
+
clear_logo=True,
|
|
28
|
+
) == {"name": "App"}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.mark.parametrize("url", ["javascript:alert(1)", "/logo.svg", "not-a-url"])
|
|
32
|
+
def test_invalid_logo_rejected(url):
|
|
33
|
+
with pytest.raises(typer.BadParameter):
|
|
34
|
+
branding_metadata({}, name="App", logo_url=url, theme=Theme.auto)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_oauth_branding_options_are_available():
|
|
38
|
+
result = CliRunner().invoke(app, ["update", "--help"])
|
|
39
|
+
assert result.exit_code == 0, result.output
|
|
40
|
+
from rich.text import Text
|
|
41
|
+
|
|
42
|
+
output = Text.from_ansi(result.output).plain
|
|
43
|
+
assert "--logo-url" in output
|
|
44
|
+
assert "--clear-logo" in output
|
|
45
|
+
assert "--theme" in output
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.asyncio
|
|
49
|
+
async def test_update_command_sends_branding_and_preserves_existing_metadata(
|
|
50
|
+
monkeypatch,
|
|
51
|
+
):
|
|
52
|
+
from unittest.mock import AsyncMock
|
|
53
|
+
|
|
54
|
+
from meshagent.api.client import OAuthClient
|
|
55
|
+
from meshagent.cli import oauth_clients
|
|
56
|
+
|
|
57
|
+
api = AsyncMock()
|
|
58
|
+
api.__aenter__.return_value = api
|
|
59
|
+
api.get_oauth_client.return_value = OAuthClient(
|
|
60
|
+
client_id="client-1",
|
|
61
|
+
project_id="project-1",
|
|
62
|
+
grant_types=["authorization_code"],
|
|
63
|
+
response_types=["code"],
|
|
64
|
+
redirect_uris=["https://example.com/callback"],
|
|
65
|
+
scope="openid",
|
|
66
|
+
metadata={"name": "Existing", "custom": "preserved"},
|
|
67
|
+
)
|
|
68
|
+
api.update_oauth_client.return_value = {"ok": True}
|
|
69
|
+
monkeypatch.setattr(oauth_clients, "get_client", AsyncMock(return_value=api))
|
|
70
|
+
monkeypatch.setattr(
|
|
71
|
+
oauth_clients, "resolve_project_id", AsyncMock(return_value="project-1")
|
|
72
|
+
)
|
|
73
|
+
monkeypatch.setattr(oauth_clients, "print_json", lambda **kwargs: None)
|
|
74
|
+
await oauth_clients.update_client(
|
|
75
|
+
client_id="client-1",
|
|
76
|
+
project_id="project-1",
|
|
77
|
+
logo_url="https://example.com/logo.svg",
|
|
78
|
+
theme=Theme.dark,
|
|
79
|
+
)
|
|
80
|
+
api.update_oauth_client.assert_awaited_once_with(
|
|
81
|
+
project_id="project-1",
|
|
82
|
+
client_id="client-1",
|
|
83
|
+
metadata={
|
|
84
|
+
"name": "Existing",
|
|
85
|
+
"custom": "preserved",
|
|
86
|
+
"logo_url": "https://example.com/logo.svg",
|
|
87
|
+
"theme": "dark",
|
|
88
|
+
},
|
|
89
|
+
)
|
|
@@ -1667,7 +1667,7 @@ def _websocket_iap_cookie_headers(
|
|
|
1667
1667
|
raise typer.BadParameter(
|
|
1668
1668
|
"a room participant token is required for --websocket-auth=iap"
|
|
1669
1669
|
)
|
|
1670
|
-
return {"Cookie": f"
|
|
1670
|
+
return {"Cookie": f"__meshagent_iap={token.strip()}"}
|
|
1671
1671
|
|
|
1672
1672
|
|
|
1673
1673
|
def _process_use_websocket_headers(
|
|
@@ -598,7 +598,7 @@ def test_process_use_websocket_headers_set_iap_cookie() -> None:
|
|
|
598
598
|
iap_token="room-jwt",
|
|
599
599
|
)
|
|
600
600
|
|
|
601
|
-
assert headers == {"Cookie": "
|
|
601
|
+
assert headers == {"Cookie": "__meshagent_iap=room-jwt"}
|
|
602
602
|
|
|
603
603
|
|
|
604
604
|
def test_process_use_websocket_headers_sign_agent_participant_token(
|
|
@@ -4,12 +4,14 @@ from pathlib import Path
|
|
|
4
4
|
from typing import Annotated, Literal
|
|
5
5
|
|
|
6
6
|
import typer
|
|
7
|
+
import yaml
|
|
7
8
|
from pydantic import BaseModel, ConfigDict
|
|
8
9
|
from pydantic_yaml import parse_yaml_raw_as
|
|
9
10
|
from rich import print
|
|
10
11
|
|
|
11
12
|
from meshagent.api import ApiScope
|
|
12
13
|
from meshagent.api.client import Meshagent, NotFoundError, ProjectInfo, ProjectsPage
|
|
14
|
+
from meshagent.api.llm_router_config import LlmRouterConfig
|
|
13
15
|
from meshagent.cli import async_typer
|
|
14
16
|
from meshagent.cli.common_options import OutputFormatOption, ProjectIdOption
|
|
15
17
|
from meshagent.cli.helper import (
|
|
@@ -282,6 +284,84 @@ async def reset_room_roles(project_id: ProjectIdOption):
|
|
|
282
284
|
await client.close()
|
|
283
285
|
|
|
284
286
|
|
|
287
|
+
@app.async_command(
|
|
288
|
+
"get-llm-router-config",
|
|
289
|
+
help=(
|
|
290
|
+
"Get the complete LLM router configuration as YAML. The document "
|
|
291
|
+
"contains allowedModels, apps, and rules."
|
|
292
|
+
),
|
|
293
|
+
)
|
|
294
|
+
async def get_llm_router_config(
|
|
295
|
+
project_id: ProjectIdOption,
|
|
296
|
+
output: Annotated[
|
|
297
|
+
Path | None,
|
|
298
|
+
typer.Option(
|
|
299
|
+
"--output", "-o", help="Write YAML to this file instead of stdout."
|
|
300
|
+
),
|
|
301
|
+
] = None,
|
|
302
|
+
):
|
|
303
|
+
client = await get_client()
|
|
304
|
+
try:
|
|
305
|
+
resolved_project_id = await resolve_project_id(project_id)
|
|
306
|
+
document = await client.get_project_settings_document(
|
|
307
|
+
resolved_project_id, "router"
|
|
308
|
+
)
|
|
309
|
+
try:
|
|
310
|
+
config = LlmRouterConfig.model_validate(document or {})
|
|
311
|
+
except ValueError as error:
|
|
312
|
+
print(f"[red]The stored LLM router configuration is invalid: {error}[/red]")
|
|
313
|
+
raise typer.Exit(code=1) from error
|
|
314
|
+
serialized = yaml.safe_dump(
|
|
315
|
+
config.to_document(),
|
|
316
|
+
sort_keys=False,
|
|
317
|
+
allow_unicode=True,
|
|
318
|
+
)
|
|
319
|
+
if output is None:
|
|
320
|
+
typer.echo(serialized, nl=False)
|
|
321
|
+
else:
|
|
322
|
+
try:
|
|
323
|
+
output.write_text(serialized)
|
|
324
|
+
except OSError as error:
|
|
325
|
+
print(f"[red]Unable to write LLM router configuration: {error}[/red]")
|
|
326
|
+
raise typer.Exit(code=1) from error
|
|
327
|
+
finally:
|
|
328
|
+
await client.close()
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
@app.async_command(
|
|
332
|
+
"set-llm-router-config",
|
|
333
|
+
help=(
|
|
334
|
+
"Validate and replace allowedModels, apps, and rules from YAML. "
|
|
335
|
+
"Providers: openai, anthropic, grok. APIs: completions, "
|
|
336
|
+
"chat_completions, responses, messages, realtime. Transports: http, "
|
|
337
|
+
"websocket. App modes: allowed, blocked. Ensure tools: web_search, "
|
|
338
|
+
"static, advice; other tool types are filter-only. Search context: "
|
|
339
|
+
"low, medium, high. Advice strategy: parallel."
|
|
340
|
+
),
|
|
341
|
+
)
|
|
342
|
+
async def set_llm_router_config(
|
|
343
|
+
file: Annotated[Path, typer.Argument(help="LLM router configuration YAML")],
|
|
344
|
+
project_id: ProjectIdOption,
|
|
345
|
+
):
|
|
346
|
+
try:
|
|
347
|
+
config = parse_yaml_raw_as(LlmRouterConfig, file.read_text())
|
|
348
|
+
except (OSError, ValueError) as error:
|
|
349
|
+
print(f"[red]Invalid LLM router configuration: {error}[/red]")
|
|
350
|
+
raise typer.Exit(code=1) from error
|
|
351
|
+
|
|
352
|
+
client = await get_client()
|
|
353
|
+
try:
|
|
354
|
+
resolved_project_id = await resolve_project_id(project_id)
|
|
355
|
+
await client.set_project_settings_document(
|
|
356
|
+
resolved_project_id,
|
|
357
|
+
"router",
|
|
358
|
+
config.to_document(),
|
|
359
|
+
)
|
|
360
|
+
print(f"[green]LLM router configuration updated:[/] {resolved_project_id}")
|
|
361
|
+
finally:
|
|
362
|
+
await client.close()
|
|
363
|
+
|
|
364
|
+
|
|
285
365
|
@app.async_command(
|
|
286
366
|
"activate", help="Set the active project for subsequent CLI commands."
|
|
287
367
|
)
|