meshagent-cli 0.49.1__tar.gz → 0.50.1__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.
Files changed (172) hide show
  1. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/PKG-INFO +17 -17
  2. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/chatbot.py +2 -0
  3. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/cli_test.py +21 -1
  4. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/containers.py +5 -3
  5. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/image.py +7 -3
  6. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/image_test.py +18 -3
  7. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/mailbot.py +2 -0
  8. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/process.py +102 -2
  9. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/process_test.py +40 -2
  10. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/room_connect.py +9 -3
  11. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/room_connect_test.py +12 -0
  12. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/rooms.py +21 -6
  13. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/rooms_test.py +60 -3
  14. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/service_accounts.py +1 -1
  15. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/service_accounts_test.py +19 -12
  16. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/services.py +75 -0
  17. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/services_test.py +67 -0
  18. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/task_runner.py +2 -0
  19. meshagent_cli-0.50.1/meshagent/cli/version.py +1 -0
  20. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/webserver.py +6 -1
  21. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/worker.py +2 -0
  22. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent_cli.egg-info/PKG-INFO +17 -17
  23. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent_cli.egg-info/requires.txt +16 -16
  24. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/pyproject.toml +16 -16
  25. meshagent_cli-0.49.1/meshagent/cli/version.py +0 -1
  26. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/LICENSE +0 -0
  27. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/README.md +0 -0
  28. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/__init__.py +0 -0
  29. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/_filedrop.py +0 -0
  30. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/agent.py +0 -0
  31. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/agent_cli_options_test.py +0 -0
  32. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/agent_package_cli.py +0 -0
  33. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/agent_package_cli_test.py +0 -0
  34. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/agents.py +0 -0
  35. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/agents_test.py +0 -0
  36. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/ask.py +0 -0
  37. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/ask_test.py +0 -0
  38. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/async_typer.py +0 -0
  39. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/async_typer_test.py +0 -0
  40. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/auth.py +0 -0
  41. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/auth_async.py +0 -0
  42. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/auth_async_test.py +0 -0
  43. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/auth_test.py +0 -0
  44. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/call.py +0 -0
  45. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/cli.py +0 -0
  46. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/cli_mcp.py +0 -0
  47. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/common_options.py +0 -0
  48. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/config.py +0 -0
  49. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/config_test.py +0 -0
  50. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/containers_test.py +0 -0
  51. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create.py +0 -0
  52. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/__init__.py +0 -0
  53. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/backend-agent/server.py +0 -0
  54. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/contact-form/server.py +0 -0
  55. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/slack-channel/channel.py +0 -0
  56. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/slack-channel/scripts/configure-slack.py +0 -0
  57. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/slack-channel/scripts/setup-slack-dev-route.py +0 -0
  58. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/slack-channel/server.py +0 -0
  59. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/task-queue-dashboard/server.py +0 -0
  60. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/telegram-channel/channel.py +0 -0
  61. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/telegram-channel/scripts/configure-telegram.py +0 -0
  62. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/telegram-channel/scripts/create-bot-token.py +0 -0
  63. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/telegram-channel/server.py +0 -0
  64. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/twilio-channel/channel.py +0 -0
  65. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/twilio-channel/server.py +0 -0
  66. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/webserver/server.py +0 -0
  67. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/whatsapp-channel/channel.py +0 -0
  68. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_project_templates/python/whatsapp-channel/server.py +0 -0
  69. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/create_test.py +0 -0
  70. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/dataset.py +0 -0
  71. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/dataset_test.py +0 -0
  72. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/developer.py +0 -0
  73. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/developer_test.py +0 -0
  74. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/doctor.py +0 -0
  75. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/doctor_dockerfiles/__init__.py +0 -0
  76. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/doctor_templates/__init__.py +0 -0
  77. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/doctor_test.py +0 -0
  78. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/feeds.py +0 -0
  79. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/feeds_test.py +0 -0
  80. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/helper.py +0 -0
  81. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/helper_test.py +0 -0
  82. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/helpers.py +0 -0
  83. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/host.py +0 -0
  84. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/iam.py +0 -0
  85. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/iam_test.py +0 -0
  86. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/launch.py +0 -0
  87. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/launch_test.py +0 -0
  88. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/llm.py +0 -0
  89. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/llm_test.py +0 -0
  90. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/local_settings.py +0 -0
  91. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/local_settings_test.py +0 -0
  92. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/mailbot_test.py +0 -0
  93. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/mailboxes.py +0 -0
  94. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/mailboxes_test.py +0 -0
  95. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/meeting_transcriber.py +0 -0
  96. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/memory.py +0 -0
  97. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/memory_test.py +0 -0
  98. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/meshagent_images.py +0 -0
  99. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/meshagent_images_test.py +0 -0
  100. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/messaging.py +0 -0
  101. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/messaging_test.py +0 -0
  102. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/mounts.py +0 -0
  103. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/multi.py +0 -0
  104. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/oci_archive.py +0 -0
  105. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/oci_archive_test.py +0 -0
  106. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/participant_token.py +0 -0
  107. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/port.py +0 -0
  108. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/port_test.py +0 -0
  109. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/preamble_rules.py +0 -0
  110. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/preamble_rules_test.py +0 -0
  111. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/process_live_test.py +0 -0
  112. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/projects.py +0 -0
  113. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/projects_test.py +0 -0
  114. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/queue.py +0 -0
  115. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/queue_test.py +0 -0
  116. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/registry.py +0 -0
  117. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/registry_test.py +0 -0
  118. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/room.py +0 -0
  119. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/room_services.py +0 -0
  120. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/room_services_test.py +0 -0
  121. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/root_commands.py +0 -0
  122. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/root_commands_test.py +0 -0
  123. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/routes.py +0 -0
  124. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/routes_test.py +0 -0
  125. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sample_channel_http_test.py +0 -0
  126. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sample_channel_live_e2e_test.py +0 -0
  127. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/scheduled_tasks.py +0 -0
  128. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/scheduled_tasks_test.py +0 -0
  129. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/secrets.py +0 -0
  130. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/secrets_test.py +0 -0
  131. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sessions.py +0 -0
  132. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sessions_test.py +0 -0
  133. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sqlite.py +0 -0
  134. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sqlite_test.py +0 -0
  135. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/storage.py +0 -0
  136. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/storage_test.py +0 -0
  137. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/subscriptions.py +0 -0
  138. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sync.py +0 -0
  139. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/sync_test.py +0 -0
  140. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/task_runner_test.py +0 -0
  141. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/test.py +0 -0
  142. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/testing.py +0 -0
  143. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/thread_inspect.py +0 -0
  144. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/thread_inspect_test.py +0 -0
  145. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/thread_sidebar.py +0 -0
  146. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tool_call_summary.py +0 -0
  147. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tool_call_summary_test.py +0 -0
  148. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tool_integrations.py +0 -0
  149. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tool_integrations_test.py +0 -0
  150. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/__init__.py +0 -0
  151. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/auth_switch.py +0 -0
  152. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/auth_switch_test.py +0 -0
  153. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/create.py +0 -0
  154. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/deploy_room.py +0 -0
  155. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/deploy_room_test.py +0 -0
  156. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/project_activate.py +0 -0
  157. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/project_activate_test.py +0 -0
  158. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/setup.py +0 -0
  159. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/setup_splash_frames.py +0 -0
  160. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/tui/setup_test.py +0 -0
  161. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/version_check.py +0 -0
  162. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/version_check_test.py +0 -0
  163. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/voicebot.py +0 -0
  164. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/volumes.py +0 -0
  165. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/volumes_test.py +0 -0
  166. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/webserver_test.py +0 -0
  167. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent/cli/worker_test.py +0 -0
  168. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent_cli.egg-info/SOURCES.txt +0 -0
  169. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent_cli.egg-info/dependency_links.txt +0 -0
  170. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent_cli.egg-info/entry_points.txt +0 -0
  171. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/meshagent_cli.egg-info/top_level.txt +0 -0
  172. {meshagent_cli-0.49.1 → meshagent_cli-0.50.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-cli
3
- Version: 0.49.1
3
+ Version: 0.50.1
4
4
  Summary: CLI for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -22,8 +22,8 @@ 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.49.1
26
- Requires-Dist: meshagent-codex==0.49.1
25
+ Requires-Dist: meshagent-llm-proxy==0.50.1
26
+ Requires-Dist: meshagent-codex==0.50.1
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.49.1; extra == "all"
36
- Requires-Dist: meshagent-api[all]==0.49.1; extra == "all"
37
- Requires-Dist: meshagent-commoncrawl==0.49.1; extra == "all"
38
- Requires-Dist: meshagent-scrapy==0.49.1; extra == "all"
39
- Requires-Dist: meshagent-computers==0.49.1; extra == "all"
40
- Requires-Dist: meshagent-openai==0.49.1; extra == "all"
41
- Requires-Dist: meshagent-anthropic==0.49.1; extra == "all"
42
- Requires-Dist: meshagent-otel==0.49.1; extra == "all"
43
- Requires-Dist: meshagent-mcp==0.49.1; extra == "all"
44
- Requires-Dist: meshagent-tools==0.49.1; extra == "all"
35
+ Requires-Dist: meshagent-agents[all]==0.50.1; extra == "all"
36
+ Requires-Dist: meshagent-api[all]==0.50.1; extra == "all"
37
+ Requires-Dist: meshagent-commoncrawl==0.50.1; extra == "all"
38
+ Requires-Dist: meshagent-scrapy==0.50.1; extra == "all"
39
+ Requires-Dist: meshagent-computers==0.50.1; extra == "all"
40
+ Requires-Dist: meshagent-openai==0.50.1; extra == "all"
41
+ Requires-Dist: meshagent-anthropic==0.50.1; extra == "all"
42
+ Requires-Dist: meshagent-otel==0.50.1; extra == "all"
43
+ Requires-Dist: meshagent-mcp==0.50.1; extra == "all"
44
+ Requires-Dist: meshagent-tools==0.50.1; 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.49.1; extra == "mcp-service"
49
- Requires-Dist: meshagent-api==0.49.1; extra == "mcp-service"
50
- Requires-Dist: meshagent-mcp==0.49.1; extra == "mcp-service"
51
- Requires-Dist: meshagent-tools==0.49.1; extra == "mcp-service"
48
+ Requires-Dist: meshagent-agents[all]==0.50.1; extra == "mcp-service"
49
+ Requires-Dist: meshagent-api==0.50.1; extra == "mcp-service"
50
+ Requires-Dist: meshagent-mcp==0.50.1; extra == "mcp-service"
51
+ Requires-Dist: meshagent-tools==0.50.1; extra == "mcp-service"
52
52
  Requires-Dist: supabase-auth~=2.28.0; extra == "mcp-service"
53
53
  Dynamic: license-file
54
54
 
@@ -1471,6 +1471,8 @@ def _build_shell_tool_env(
1471
1471
  env["MESHAGENT_TOKEN"] = room.protocol.token
1472
1472
  env["OPENAI_API_KEY"] = room.protocol.token
1473
1473
  env["ANTHROPIC_API_KEY"] = room.protocol.token
1474
+ env["GROK_API_KEY"] = room.protocol.token
1475
+ env["XAI_API_KEY"] = room.protocol.token
1474
1476
  return env
1475
1477
 
1476
1478
 
@@ -4,7 +4,7 @@ import types
4
4
 
5
5
  import pytest
6
6
 
7
- from meshagent.api import RoomException
7
+ from meshagent.api import RoomDisabledError, RoomException
8
8
  from meshagent.agents import channel_process
9
9
  from meshagent.cli import async_typer
10
10
  from meshagent.cli import cli
@@ -134,6 +134,26 @@ def test_app_prints_room_exception_without_traceback(capsys) -> None:
134
134
  assert captured.out == ""
135
135
 
136
136
 
137
+ def test_app_prints_disabled_room_message_and_exits_nonzero(capsys) -> None:
138
+ app = async_typer.AsyncTyper()
139
+
140
+ @app.callback()
141
+ def app_callback() -> None:
142
+ pass
143
+
144
+ @app.command("connect")
145
+ def connect_command() -> None:
146
+ raise RoomDisabledError()
147
+
148
+ with pytest.raises(SystemExit) as exc_info:
149
+ app(["connect"])
150
+
151
+ assert exc_info.value.code == 1
152
+ captured = capsys.readouterr()
153
+ assert captured.err == "This room is currently disabled.\n"
154
+ assert captured.out == ""
155
+
156
+
137
157
  def test_main_exits_with_status_returned_by_async_typer(monkeypatch) -> None:
138
158
  monkeypatch.setattr(channel_process, "dispatch_main", lambda **kwargs: False)
139
159
  monkeypatch.setattr(cli, "app", lambda: 23)
@@ -780,12 +780,14 @@ async def run_container(
780
780
  "--template",
781
781
  help=(
782
782
  "Allowed values: agent, none. agent: MeshAgent mounts room storage "
783
- "at /data, sets MESHAGENT_TOKEN, OPENAI_API_KEY, and "
784
- "ANTHROPIC_API_KEY to a container-scoped MeshAgent token. agent "
783
+ "at /data, sets MESHAGENT_TOKEN, OPENAI_API_KEY, "
784
+ "ANTHROPIC_API_KEY, GROK_API_KEY, and XAI_API_KEY to a "
785
+ "container-scoped MeshAgent token. agent "
785
786
  "also sets SMTP_PASSWORD to that token, SMTP_USERNAME to the "
786
787
  "container name, SMTP_PORT to 587, SMTP_HOSTNAME from "
787
788
  "MESHAGENT_MAIL_DOMAIN when available, plus OPENAI_BASE_URL, "
788
- "ANTHROPIC_BASE_URL, MESHAGENT_API_URL, MESHAGENT_ROOM_URL, "
789
+ "ANTHROPIC_BASE_URL, GROK_BASE_URL, XAI_BASE_URL, "
790
+ "MESHAGENT_API_URL, MESHAGENT_ROOM_URL, "
789
791
  "MESHAGENT_ROOM, MESHAGENT_PROJECT_ID, MESHAGENT_SESSION_ID, "
790
792
  "OTEL_ENDPOINT, OTEL_PYTHON_LOG_LEVEL, and MESHAGENT_MAIL_DOMAIN "
791
793
  "from the room runtime when available. Manual env values win. "
@@ -140,6 +140,8 @@ _TOKEN_ENVIRONMENT_NAMES = (
140
140
  "MESHAGENT_TOKEN",
141
141
  "OPENAI_API_KEY",
142
142
  "ANTHROPIC_API_KEY",
143
+ "GROK_API_KEY",
144
+ "XAI_API_KEY",
143
145
  )
144
146
  _DEFAULT_MESHAGENT_IMAGE_PREFIX = PROD_MESHAGENT_IMAGE_PREFIX
145
147
  _IMAGE_TAG_RE = re.compile(r"^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$")
@@ -4584,12 +4586,14 @@ async def deploy_image(
4584
4586
  "--template",
4585
4587
  help=(
4586
4588
  "Allowed values: agent, none. agent: MeshAgent mounts room storage "
4587
- "at /data, sets MESHAGENT_TOKEN, OPENAI_API_KEY, and "
4588
- "ANTHROPIC_API_KEY to a container-scoped MeshAgent token. agent "
4589
+ "at /data, sets MESHAGENT_TOKEN, OPENAI_API_KEY, "
4590
+ "ANTHROPIC_API_KEY, GROK_API_KEY, and XAI_API_KEY to a "
4591
+ "container-scoped MeshAgent token. agent "
4589
4592
  "also sets SMTP_PASSWORD to that token, SMTP_USERNAME to the "
4590
4593
  "container name, SMTP_PORT to 587, SMTP_HOSTNAME from "
4591
4594
  "MESHAGENT_MAIL_DOMAIN when available, plus OPENAI_BASE_URL, "
4592
- "ANTHROPIC_BASE_URL, MESHAGENT_API_URL, MESHAGENT_ROOM_URL, "
4595
+ "ANTHROPIC_BASE_URL, GROK_BASE_URL, XAI_BASE_URL, "
4596
+ "MESHAGENT_API_URL, MESHAGENT_ROOM_URL, "
4593
4597
  "MESHAGENT_ROOM, MESHAGENT_PROJECT_ID, MESHAGENT_SESSION_ID, "
4594
4598
  "OTEL_ENDPOINT, OTEL_PYTHON_LOG_LEVEL, and MESHAGENT_MAIL_DOMAIN "
4595
4599
  "from the room runtime when available. Manual env values win. "
@@ -3131,7 +3131,12 @@ async def test_deploy_image_creates_room_service_with_mounts_env_secret_and_toke
3131
3131
  assert env_by_name["MESHAGENT_TOKEN"].token.api.secrets is None
3132
3132
  assert env_by_name["MESHAGENT_TOKEN"].token.api.services is not None
3133
3133
  assert env_by_name["MESHAGENT_TOKEN"].token.role == "agent"
3134
- for env_name in ("OPENAI_API_KEY", "ANTHROPIC_API_KEY"):
3134
+ for env_name in (
3135
+ "OPENAI_API_KEY",
3136
+ "ANTHROPIC_API_KEY",
3137
+ "GROK_API_KEY",
3138
+ "XAI_API_KEY",
3139
+ ):
3135
3140
  assert env_by_name[env_name].token is not None
3136
3141
  assert env_by_name[env_name].token == env_by_name["MESHAGENT_TOKEN"].token
3137
3142
  assert "restarted_service_id" not in captured
@@ -3208,7 +3213,12 @@ async def test_deploy_image_identity_overrides_env_secret_and_token_identity(
3208
3213
  assert env_by_name["APP_SECRET"].secret == SecretValue(id="secret-1")
3209
3214
  assert env_by_name["MESHAGENT_TOKEN"].token is not None
3210
3215
  assert env_by_name["MESHAGENT_TOKEN"].token.identity == "custom-agent"
3211
- for env_name in ("OPENAI_API_KEY", "ANTHROPIC_API_KEY"):
3216
+ for env_name in (
3217
+ "OPENAI_API_KEY",
3218
+ "ANTHROPIC_API_KEY",
3219
+ "GROK_API_KEY",
3220
+ "XAI_API_KEY",
3221
+ ):
3212
3222
  assert env_by_name[env_name].token is not None
3213
3223
  assert env_by_name[env_name].token == env_by_name["MESHAGENT_TOKEN"].token
3214
3224
  assert captured["room_client_closed"] is True
@@ -5252,7 +5262,12 @@ async def test_deploy_image_updates_existing_service_route_and_replaces_environm
5252
5262
  assert env_by_name["MESHAGENT_TOKEN"].token.api.admin is not None
5253
5263
  assert env_by_name["MESHAGENT_TOKEN"].token.api.secrets is None
5254
5264
  assert env_by_name["MESHAGENT_TOKEN"].token.api.tunnels is not None
5255
- for env_name in ("OPENAI_API_KEY", "ANTHROPIC_API_KEY"):
5265
+ for env_name in (
5266
+ "OPENAI_API_KEY",
5267
+ "ANTHROPIC_API_KEY",
5268
+ "GROK_API_KEY",
5269
+ "XAI_API_KEY",
5270
+ ):
5256
5271
  assert env_by_name[env_name].token is not None
5257
5272
  assert env_by_name[env_name].token == env_by_name["MESHAGENT_TOKEN"].token
5258
5273
  assert updated_spec.ports is not None
@@ -395,6 +395,8 @@ def build_mailbot(
395
395
  env["MESHAGENT_TOKEN"] = self.room.protocol.token
396
396
  env["OPENAI_API_KEY"] = self.room.protocol.token
397
397
  env["ANTHROPIC_API_KEY"] = self.room.protocol.token
398
+ env["GROK_API_KEY"] = self.room.protocol.token
399
+ env["XAI_API_KEY"] = self.room.protocol.token
398
400
 
399
401
  if require_shell:
400
402
  if supports_openai_shell:
@@ -2178,6 +2178,7 @@ ThreadStorageBackends = ThreadStorageBackend | str | list[str] | tuple[str, ...]
2178
2178
  DEFAULT_PROCESS_THREAD_STORAGE_BACKENDS: tuple[str, ...] = ("dataset",)
2179
2179
  ContextManagementMode = Literal["auto", "standalone", "none"]
2180
2180
  ProcessToolSearchMode = Literal["room", "agent", "none"]
2181
+ LlmDelegationPolicy = Literal["required", "optional"]
2181
2182
 
2182
2183
  ShellCopyEnvOption = Annotated[
2183
2184
  list[str],
@@ -3471,9 +3472,19 @@ def _provider_name_for_model(model: str) -> str:
3471
3472
  return "openai-realtime"
3472
3473
  if model.startswith("claude-"):
3473
3474
  return "anthropic"
3475
+ if model.startswith("grok-"):
3476
+ return "grok"
3474
3477
  return "openai"
3475
3478
 
3476
3479
 
3480
+ def _grok_base_url() -> str:
3481
+ for name in ("GROK_BASE_URL", "XAI_BASE_URL"):
3482
+ value = os.getenv(name)
3483
+ if value is not None and value.strip() != "":
3484
+ return value.strip()
3485
+ raise ValueError("GROK_BASE_URL or XAI_BASE_URL is required for Grok models")
3486
+
3487
+
3477
3488
  def _normalize_thread_storage_backend(
3478
3489
  thread_storage: str,
3479
3490
  ) -> NormalizedThreadStorageBackend:
@@ -4324,7 +4335,7 @@ def _format_model_list(
4324
4335
 
4325
4336
 
4326
4337
  def _supports_openai_responses_builtin_tools(*, model: str) -> bool:
4327
- return _provider_name_for_model(model) == "openai"
4338
+ return _provider_name_for_model(model) in {"openai", "grok"}
4328
4339
 
4329
4340
 
4330
4341
  def _supports_anthropic_builtin_tools(*, model: str) -> bool:
@@ -4337,7 +4348,8 @@ def _has_openai_responses_provider(
4337
4348
  if llm_participant is not None:
4338
4349
  return False
4339
4350
  return any(
4340
- spec.backend == "llm" and spec.provider == "openai" for spec in model_specs
4351
+ spec.backend == "llm" and spec.provider in {"openai", "grok"}
4352
+ for spec in model_specs
4341
4353
  )
4342
4354
 
4343
4355
 
@@ -4355,6 +4367,16 @@ def _build_decision_llm_adapter(
4355
4367
  log_requests=log_llm_requests,
4356
4368
  )
4357
4369
 
4370
+ if decision_model.startswith("grok-"):
4371
+ return OpenAIResponsesAdapter(
4372
+ model=decision_model,
4373
+ provider="grok",
4374
+ base_url=_grok_base_url(),
4375
+ api_key=api_key,
4376
+ mode="request",
4377
+ log_requests=log_llm_requests,
4378
+ )
4379
+
4358
4380
  client = _openai_proxy_client(
4359
4381
  api_key=api_key,
4360
4382
  meshagent_project_id=meshagent_project_id,
@@ -4701,6 +4723,7 @@ def _build_runtime_agent(
4701
4723
  verbose_dataset: bool = False,
4702
4724
  save_audio_input: bool = False,
4703
4725
  preamble_rule: bool = True,
4726
+ llm_delegation: LlmDelegationPolicy = "optional",
4704
4727
  ):
4705
4728
  builder = _builder_for_runtime(runtime)
4706
4729
  selected_models = (
@@ -4790,6 +4813,7 @@ def _build_runtime_agent(
4790
4813
  builder_kwargs["preamble_rule"] = preamble_rule
4791
4814
  builder_kwargs["websocket_auth"] = websocket_auth
4792
4815
  builder_kwargs["room_token"] = room_token
4816
+ builder_kwargs["llm_delegation"] = llm_delegation
4793
4817
  return builder(**builder_kwargs)
4794
4818
 
4795
4819
 
@@ -4857,6 +4881,8 @@ def _build_shell_tool_env(
4857
4881
  env["MESHAGENT_TOKEN"] = room.protocol.token
4858
4882
  env["OPENAI_API_KEY"] = room.protocol.token
4859
4883
  env["ANTHROPIC_API_KEY"] = room.protocol.token
4884
+ env["GROK_API_KEY"] = room.protocol.token
4885
+ env["XAI_API_KEY"] = room.protocol.token
4860
4886
  return env
4861
4887
 
4862
4888
 
@@ -5061,9 +5087,13 @@ def build_chatbot(
5061
5087
  if resolved_decision_model is None:
5062
5088
  resolved_decision_model = _DEFAULT_OPENAI_REALTIME_DECISION_MODEL
5063
5089
  else:
5090
+ is_grok_model = model.startswith("grok-")
5064
5091
  llm_adapter = OpenAIResponsesAdapter(
5065
5092
  model=model,
5093
+ provider="grok" if is_grok_model else "openai",
5094
+ base_url=_grok_base_url() if is_grok_model else None,
5066
5095
  api_key=api_key,
5096
+ mode="request" if is_grok_model else "websocket",
5067
5097
  log_requests=log_llm_requests,
5068
5098
  )
5069
5099
 
@@ -5482,6 +5512,7 @@ def build_process_agent(
5482
5512
  verbose_dataset: bool = False,
5483
5513
  save_audio_input: bool = False,
5484
5514
  preamble_rule: bool = True,
5515
+ llm_delegation: LlmDelegationPolicy = "optional",
5485
5516
  ):
5486
5517
  from meshagent.agents import (
5487
5518
  AgentMessageThreadStatusPublisher,
@@ -5698,6 +5729,7 @@ def build_process_agent(
5698
5729
  openai_models: list[str] = []
5699
5730
  realtime_models: list[str] = []
5700
5731
  anthropic_models: list[str] = []
5732
+ grok_models: list[str] = []
5701
5733
  provider_order: list[str] = []
5702
5734
  for selected_spec in llm_model_specs:
5703
5735
  selected_model = selected_spec.model
@@ -5711,6 +5743,9 @@ def build_process_agent(
5711
5743
  elif provider_name == "anthropic":
5712
5744
  if selected_model not in anthropic_models:
5713
5745
  anthropic_models.append(selected_model)
5746
+ elif provider_name == "grok":
5747
+ if selected_model not in grok_models:
5748
+ grok_models.append(selected_model)
5714
5749
  elif selected_model not in openai_models:
5715
5750
  openai_models.append(selected_model)
5716
5751
 
@@ -5777,6 +5812,24 @@ def build_process_agent(
5777
5812
  allowed_models=None if unfiltered_llm_backend else anthropic_models,
5778
5813
  ),
5779
5814
  )
5815
+ if grok_models:
5816
+ providers_by_name["grok"] = LLMProvider(
5817
+ name="grok",
5818
+ adapter=OpenAIResponsesAdapter(
5819
+ model=grok_models[0],
5820
+ provider="grok",
5821
+ base_url=_grok_base_url(),
5822
+ api_key=api_key,
5823
+ mode="request",
5824
+ log_requests=log_llm_requests,
5825
+ context_management=context_management,
5826
+ compaction_threshold=compaction_threshold,
5827
+ max_output_tokens=max_output_tokens,
5828
+ reasoning_effort=reasoning_effort,
5829
+ tool_search="server" if tool_search != "none" else None,
5830
+ allowed_models=None if unfiltered_llm_backend else grok_models,
5831
+ ),
5832
+ )
5780
5833
  for provider_name in provider_order:
5781
5834
  provider = providers_by_name.get(provider_name)
5782
5835
  if provider is not None:
@@ -6108,6 +6161,12 @@ def build_process_agent(
6108
6161
  connection = await provider.adapter.create_realtime_connection(
6109
6162
  protocol=protocol,
6110
6163
  model=resolved_model,
6164
+ llm_authorization_token=(
6165
+ start_thread.llm_authorization.token
6166
+ if start_thread.llm_authorization is not None
6167
+ and not start_thread.llm_authorization.is_expired()
6168
+ else None
6169
+ ),
6111
6170
  )
6112
6171
  return AgentRealtimeConnectionInfo(
6113
6172
  protocol=connection.protocol,
@@ -6936,6 +6995,7 @@ def build_process_agent(
6936
6995
  turns=turns,
6937
6996
  )
6938
6997
  ),
6998
+ llm_delegation=llm_delegation,
6939
6999
  )
6940
7000
  if room is not None:
6941
7001
  process.register_content_scheme(_room_content_scheme(room=room))
@@ -7194,6 +7254,13 @@ async def join(
7194
7254
  Optional[str],
7195
7255
  typer.Option(..., help="Delegate LLM interactions to a remote participant"),
7196
7256
  ] = None,
7257
+ llm_delegation: Annotated[
7258
+ LlmDelegationPolicy,
7259
+ typer.Option(
7260
+ "--llm-delegation",
7261
+ help="Require per-turn LLM delegation or allow it when provided.",
7262
+ ),
7263
+ ] = "optional",
7197
7264
  decision_model: DecisionModelOption = None,
7198
7265
  transcription_model: TranscriptionModelOption = (
7199
7266
  DEFAULT_OPENAI_REALTIME_TRANSCRIPTION_MODEL
@@ -7403,6 +7470,7 @@ async def join(
7403
7470
  require_discovery=require_discovery,
7404
7471
  require_advanced_shell=require_advanced_shell,
7405
7472
  llm_participant=llm_participant,
7473
+ llm_delegation=llm_delegation,
7406
7474
  decision_model=decision_model,
7407
7475
  transcription_model=transcription_model,
7408
7476
  voice=voice,
@@ -7689,6 +7757,13 @@ async def service(
7689
7757
  Optional[str],
7690
7758
  typer.Option(..., help="Delegate LLM interactions to a remote participant"),
7691
7759
  ] = None,
7760
+ llm_delegation: Annotated[
7761
+ LlmDelegationPolicy,
7762
+ typer.Option(
7763
+ "--llm-delegation",
7764
+ help="Require per-turn LLM delegation or allow it when provided.",
7765
+ ),
7766
+ ] = "optional",
7692
7767
  decision_model: DecisionModelOption = None,
7693
7768
  transcription_model: TranscriptionModelOption = (
7694
7769
  DEFAULT_OPENAI_REALTIME_TRANSCRIPTION_MODEL
@@ -7865,6 +7940,7 @@ async def service(
7865
7940
  require_discovery=require_discovery,
7866
7941
  require_advanced_shell=require_advanced_shell,
7867
7942
  llm_participant=llm_participant,
7943
+ llm_delegation=llm_delegation,
7868
7944
  decision_model=decision_model,
7869
7945
  transcription_model=transcription_model,
7870
7946
  voice=voice,
@@ -8125,6 +8201,13 @@ async def spec(
8125
8201
  Optional[str],
8126
8202
  typer.Option(..., help="Delegate LLM interactions to a remote participant"),
8127
8203
  ] = None,
8204
+ llm_delegation: Annotated[
8205
+ LlmDelegationPolicy,
8206
+ typer.Option(
8207
+ "--llm-delegation",
8208
+ help="Require per-turn LLM delegation or allow it when provided.",
8209
+ ),
8210
+ ] = "optional",
8128
8211
  decision_model: DecisionModelOption = None,
8129
8212
  transcription_model: TranscriptionModelOption = (
8130
8213
  DEFAULT_OPENAI_REALTIME_TRANSCRIPTION_MODEL
@@ -8281,6 +8364,7 @@ async def spec(
8281
8364
  require_discovery=require_discovery,
8282
8365
  require_advanced_shell=require_advanced_shell,
8283
8366
  llm_participant=llm_participant,
8367
+ llm_delegation=llm_delegation,
8284
8368
  decision_model=decision_model,
8285
8369
  transcription_model=transcription_model,
8286
8370
  voice=voice,
@@ -8557,6 +8641,13 @@ async def deploy(
8557
8641
  Optional[str],
8558
8642
  typer.Option(..., help="Delegate LLM interactions to a remote participant"),
8559
8643
  ] = None,
8644
+ llm_delegation: Annotated[
8645
+ LlmDelegationPolicy,
8646
+ typer.Option(
8647
+ "--llm-delegation",
8648
+ help="Require per-turn LLM delegation or allow it when provided.",
8649
+ ),
8650
+ ] = "optional",
8560
8651
  decision_model: DecisionModelOption = None,
8561
8652
  transcription_model: TranscriptionModelOption = (
8562
8653
  DEFAULT_OPENAI_REALTIME_TRANSCRIPTION_MODEL
@@ -8716,6 +8807,7 @@ async def deploy(
8716
8807
  require_discovery=require_discovery,
8717
8808
  require_advanced_shell=require_advanced_shell,
8718
8809
  llm_participant=llm_participant,
8810
+ llm_delegation=llm_delegation,
8719
8811
  decision_model=decision_model,
8720
8812
  transcription_model=transcription_model,
8721
8813
  voice=voice,
@@ -11061,6 +11153,13 @@ async def run(
11061
11153
  Optional[str],
11062
11154
  typer.Option(..., help="Delegate LLM interactions to a remote participant"),
11063
11155
  ] = None,
11156
+ llm_delegation: Annotated[
11157
+ LlmDelegationPolicy,
11158
+ typer.Option(
11159
+ "--llm-delegation",
11160
+ help="Require per-turn LLM delegation or allow it when provided.",
11161
+ ),
11162
+ ] = "optional",
11064
11163
  decision_model: DecisionModelOption = None,
11065
11164
  transcription_model: TranscriptionModelOption = (
11066
11165
  DEFAULT_OPENAI_REALTIME_TRANSCRIPTION_MODEL
@@ -11375,6 +11474,7 @@ async def run(
11375
11474
  require_discovery=require_discovery,
11376
11475
  require_advanced_shell=require_advanced_shell,
11377
11476
  llm_participant=llm_participant,
11477
+ llm_delegation=llm_delegation,
11378
11478
  decision_model=decision_model,
11379
11479
  transcription_model=transcription_model,
11380
11480
  voice=voice,
@@ -1420,6 +1420,7 @@ def test_build_process_agent_passes_custom_realtime_transcription_model(
1420
1420
  def test_build_process_agent_groups_repeated_models_by_provider(
1421
1421
  monkeypatch: pytest.MonkeyPatch,
1422
1422
  ) -> None:
1423
+ monkeypatch.setenv("GROK_BASE_URL", "https://grok.example.test/v1")
1423
1424
  created_adapters: list[dict[str, object]] = []
1424
1425
 
1425
1426
  class _FakeOpenAIAdapter:
@@ -1437,6 +1438,9 @@ def test_build_process_agent_groups_repeated_models_by_provider(
1437
1438
  response_options=None,
1438
1439
  tool_search=None,
1439
1440
  allowed_models=None,
1441
+ provider="openai",
1442
+ base_url=None,
1443
+ mode="websocket",
1440
1444
  ) -> None:
1441
1445
  del api_key
1442
1446
  del client
@@ -1447,9 +1451,11 @@ def test_build_process_agent_groups_repeated_models_by_provider(
1447
1451
  del reasoning_effort
1448
1452
  del response_options
1449
1453
  del tool_search
1454
+ del base_url
1455
+ del mode
1450
1456
  created_adapters.append(
1451
1457
  {
1452
- "provider": "openai",
1458
+ "provider": provider,
1453
1459
  "model": model,
1454
1460
  "allowed_models": allowed_models,
1455
1461
  }
@@ -1514,7 +1520,13 @@ def test_build_process_agent_groups_repeated_models_by_provider(
1514
1520
  )
1515
1521
 
1516
1522
  agent_cls = process.build_process_agent(
1517
- model=["gpt-5.6-sol", "gpt-5.4", "claude-opus-4-7", "gpt-realtime"],
1523
+ model=[
1524
+ "gpt-5.6-sol",
1525
+ "gpt-5.4",
1526
+ "claude-opus-4-7",
1527
+ "gpt-realtime",
1528
+ "grok-4.6",
1529
+ ],
1518
1530
  rule=[],
1519
1531
  toolkit=[],
1520
1532
  schema=[],
@@ -1540,9 +1552,31 @@ def test_build_process_agent_groups_repeated_models_by_provider(
1540
1552
  "model": "claude-opus-4-7",
1541
1553
  "allowed_models": ["claude-opus-4-7"],
1542
1554
  },
1555
+ {
1556
+ "provider": "grok",
1557
+ "model": "grok-4.6",
1558
+ "allowed_models": ["grok-4.6"],
1559
+ },
1543
1560
  ]
1544
1561
 
1545
1562
 
1563
+ def test_grok_base_url_never_falls_back_to_openai(
1564
+ monkeypatch: pytest.MonkeyPatch,
1565
+ ) -> None:
1566
+ monkeypatch.setenv("OPENAI_BASE_URL", "https://openai.example.test/v1")
1567
+ monkeypatch.delenv("GROK_BASE_URL", raising=False)
1568
+ monkeypatch.delenv("XAI_BASE_URL", raising=False)
1569
+
1570
+ with pytest.raises(
1571
+ ValueError,
1572
+ match="GROK_BASE_URL or XAI_BASE_URL is required for Grok models",
1573
+ ):
1574
+ process._grok_base_url()
1575
+
1576
+ monkeypatch.setenv("XAI_BASE_URL", " https://xai.example.test/v1 ")
1577
+ assert process._grok_base_url() == "https://xai.example.test/v1"
1578
+
1579
+
1546
1580
  def test_build_process_agent_passes_project_header_client_to_openai_adapters(
1547
1581
  monkeypatch: pytest.MonkeyPatch,
1548
1582
  ) -> None:
@@ -7075,6 +7109,8 @@ async def test_chatbot_require_advanced_shell_uses_container_toolkit_with_shell_
7075
7109
  "MESHAGENT_TOKEN": "test-token",
7076
7110
  "OPENAI_API_KEY": "test-token",
7077
7111
  "ANTHROPIC_API_KEY": "test-token",
7112
+ "GROK_API_KEY": "test-token",
7113
+ "XAI_API_KEY": "test-token",
7078
7114
  }
7079
7115
 
7080
7116
 
@@ -7124,6 +7160,8 @@ async def test_process_agent_require_advanced_shell_uses_container_toolkit_with_
7124
7160
  "MESHAGENT_TOKEN": "token",
7125
7161
  "OPENAI_API_KEY": "token",
7126
7162
  "ANTHROPIC_API_KEY": "token",
7163
+ "GROK_API_KEY": "token",
7164
+ "XAI_API_KEY": "token",
7127
7165
  }
7128
7166
  finally:
7129
7167
  await agent.stop()
@@ -29,6 +29,8 @@ _CONNECTED_TOKEN_ENV_NAMES = (
29
29
  "MESHAGENT_TOKEN",
30
30
  "OPENAI_API_KEY",
31
31
  "ANTHROPIC_API_KEY",
32
+ "GROK_API_KEY",
33
+ "XAI_API_KEY",
32
34
  )
33
35
 
34
36
  if TYPE_CHECKING:
@@ -500,6 +502,8 @@ async def _build_connected_command_env(
500
502
  child_env["MESHAGENT_ROOM"] = room_env.room_name
501
503
  child_env["OPENAI_BASE_URL"] = f"{api_url}/openai/v1"
502
504
  child_env["ANTHROPIC_BASE_URL"] = f"{api_url}/anthropic"
505
+ child_env["GROK_BASE_URL"] = f"{api_url}/grok/v1"
506
+ child_env["XAI_BASE_URL"] = child_env["GROK_BASE_URL"]
503
507
  _set_connected_token_environment(
504
508
  child_env=child_env,
505
509
  connected_token=connected_token,
@@ -528,7 +532,8 @@ app = async_typer.AsyncTyper(add_completion=False)
528
532
  help=(
529
533
  "Connect to a room and run a local command with "
530
534
  "MESHAGENT_API_URL, MESHAGENT_PROJECT_ID, MESHAGENT_TOKEN, "
531
- "OPENAI_API_KEY, ANTHROPIC_API_KEY, and MESHAGENT_ROOM set by "
535
+ "OPENAI_API_KEY, ANTHROPIC_API_KEY, GROK_API_KEY, XAI_API_KEY, and "
536
+ "MESHAGENT_ROOM set by "
532
537
  "the default agent template. Use -- before the local command."
533
538
  ),
534
539
  )
@@ -580,8 +585,9 @@ def _connect_command(
580
585
  show_default=True,
581
586
  help=(
582
587
  "Allowed values: agent, none. agent: MeshAgent sets MESHAGENT_TOKEN, "
583
- "OPENAI_API_KEY, and ANTHROPIC_API_KEY to a room-scoped MeshAgent token, "
584
- "and sets OPENAI_BASE_URL, ANTHROPIC_BASE_URL, MESHAGENT_API_URL, "
588
+ "OPENAI_API_KEY, ANTHROPIC_API_KEY, GROK_API_KEY, and XAI_API_KEY to a "
589
+ "room-scoped MeshAgent token, and sets OPENAI_BASE_URL, "
590
+ "ANTHROPIC_BASE_URL, GROK_BASE_URL, XAI_BASE_URL, MESHAGENT_API_URL, "
585
591
  "MESHAGENT_PROJECT_ID, and MESHAGENT_ROOM for the connected room unless "
586
592
  "manually set. Provider base URLs use the project API endpoint. none: "
587
593
  "MeshAgent applies no template defaults."
@@ -440,6 +440,10 @@ def test_room_connect_runs_command_with_connected_room_env(
440
440
  assert captured_env["ANTHROPIC_BASE_URL"] == "https://env.meshagent.test/anthropic"
441
441
  assert captured_env["OPENAI_API_KEY"] == "room-jwt"
442
442
  assert captured_env["ANTHROPIC_API_KEY"] == "room-jwt"
443
+ assert captured_env["GROK_BASE_URL"] == "https://env.meshagent.test/grok/v1"
444
+ assert captured_env["XAI_BASE_URL"] == captured_env["GROK_BASE_URL"]
445
+ assert captured_env["GROK_API_KEY"] == "room-jwt"
446
+ assert captured_env["XAI_API_KEY"] == "room-jwt"
443
447
 
444
448
 
445
449
  def test_room_connect_ignores_ambient_participant_token_for_other_room(
@@ -561,13 +565,21 @@ async def test_room_connect_env_satisfies_llm_proxy_docs_samples(
561
565
  "OPENAI_API_KEY",
562
566
  "ANTHROPIC_BASE_URL",
563
567
  "ANTHROPIC_API_KEY",
568
+ "GROK_BASE_URL",
569
+ "GROK_API_KEY",
570
+ "XAI_BASE_URL",
571
+ "XAI_API_KEY",
564
572
  }
565
573
  assert sample_required_env <= child_env.keys()
566
574
  assert child_env["MESHAGENT_TOKEN"] == "room-jwt"
567
575
  assert child_env["OPENAI_API_KEY"] == child_env["MESHAGENT_TOKEN"]
568
576
  assert child_env["ANTHROPIC_API_KEY"] == child_env["MESHAGENT_TOKEN"]
577
+ assert child_env["GROK_API_KEY"] == child_env["MESHAGENT_TOKEN"]
578
+ assert child_env["XAI_API_KEY"] == child_env["MESHAGENT_TOKEN"]
569
579
  assert child_env["OPENAI_BASE_URL"] == "https://env.meshagent.test/openai/v1"
570
580
  assert child_env["ANTHROPIC_BASE_URL"] == "https://env.meshagent.test/anthropic"
581
+ assert child_env["GROK_BASE_URL"] == "https://env.meshagent.test/grok/v1"
582
+ assert child_env["XAI_BASE_URL"] == child_env["GROK_BASE_URL"]
571
583
 
572
584
 
573
585
  @pytest.mark.asyncio