meshagent-cli 0.6.1__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.
Potentially problematic release.
This version of meshagent-cli might be problematic. Click here for more details.
- meshagent/cli/__init__.py +3 -0
- meshagent/cli/agent.py +263 -0
- meshagent/cli/api_keys.py +102 -0
- meshagent/cli/async_typer.py +31 -0
- meshagent/cli/auth.py +30 -0
- meshagent/cli/auth_async.py +295 -0
- meshagent/cli/call.py +224 -0
- meshagent/cli/chatbot.py +311 -0
- meshagent/cli/cli.py +184 -0
- meshagent/cli/cli_mcp.py +344 -0
- meshagent/cli/cli_secrets.py +414 -0
- meshagent/cli/common_options.py +23 -0
- meshagent/cli/containers.py +577 -0
- meshagent/cli/developer.py +70 -0
- meshagent/cli/exec.py +381 -0
- meshagent/cli/helper.py +147 -0
- meshagent/cli/helpers.py +131 -0
- meshagent/cli/mailbot.py +260 -0
- meshagent/cli/meeting_transcriber.py +124 -0
- meshagent/cli/messaging.py +160 -0
- meshagent/cli/oauth2.py +189 -0
- meshagent/cli/participant_token.py +61 -0
- meshagent/cli/projects.py +105 -0
- meshagent/cli/queue.py +91 -0
- meshagent/cli/services.py +490 -0
- meshagent/cli/sessions.py +26 -0
- meshagent/cli/storage.py +813 -0
- meshagent/cli/version.py +1 -0
- meshagent/cli/voicebot.py +178 -0
- meshagent/cli/webhook.py +100 -0
- meshagent_cli-0.6.1.dist-info/METADATA +47 -0
- meshagent_cli-0.6.1.dist-info/RECORD +35 -0
- meshagent_cli-0.6.1.dist-info/WHEEL +5 -0
- meshagent_cli-0.6.1.dist-info/entry_points.txt +2 -0
- meshagent_cli-0.6.1.dist-info/top_level.txt +1 -0
meshagent/cli/mailbot.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from meshagent.api import ParticipantToken
|
|
3
|
+
from rich import print
|
|
4
|
+
from typing import Annotated, Optional
|
|
5
|
+
from meshagent.cli.common_options import (
|
|
6
|
+
ProjectIdOption,
|
|
7
|
+
RoomOption,
|
|
8
|
+
)
|
|
9
|
+
from meshagent.tools import Toolkit
|
|
10
|
+
from meshagent.api import RoomClient, WebSocketClientProtocol, ApiScope
|
|
11
|
+
from meshagent.api.helpers import meshagent_base_url, websocket_room_url
|
|
12
|
+
from meshagent.cli import async_typer
|
|
13
|
+
from meshagent.cli.helper import (
|
|
14
|
+
get_client,
|
|
15
|
+
resolve_project_id,
|
|
16
|
+
resolve_room,
|
|
17
|
+
resolve_key,
|
|
18
|
+
)
|
|
19
|
+
from meshagent.openai import OpenAIResponsesAdapter
|
|
20
|
+
from meshagent.openai.tools.responses_adapter import ImageGenerationTool, LocalShellTool
|
|
21
|
+
from meshagent.api.services import ServiceHost
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
from typing import List
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
from meshagent.api import RequiredToolkit, RequiredSchema
|
|
28
|
+
from meshagent.openai.tools.responses_adapter import WebSearchTool
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
app = async_typer.AsyncTyper(help="Join a mailbot to a room")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def build_mailbot(
|
|
35
|
+
*,
|
|
36
|
+
model: str,
|
|
37
|
+
agent_name: str,
|
|
38
|
+
rule: List[str],
|
|
39
|
+
toolkit: List[str],
|
|
40
|
+
schema: List[str],
|
|
41
|
+
image_generation: Optional[str] = None,
|
|
42
|
+
local_shell: bool,
|
|
43
|
+
computer_use: bool,
|
|
44
|
+
rules_file: Optional[str] = None,
|
|
45
|
+
web_search: Annotated[
|
|
46
|
+
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
47
|
+
] = False,
|
|
48
|
+
queue: str,
|
|
49
|
+
):
|
|
50
|
+
from meshagent.agents.mail import MailWorker
|
|
51
|
+
|
|
52
|
+
requirements = []
|
|
53
|
+
|
|
54
|
+
toolkits = []
|
|
55
|
+
|
|
56
|
+
for t in toolkit:
|
|
57
|
+
requirements.append(RequiredToolkit(name=t))
|
|
58
|
+
|
|
59
|
+
for t in schema:
|
|
60
|
+
requirements.append(RequiredSchema(name=t))
|
|
61
|
+
|
|
62
|
+
if rules_file is not None:
|
|
63
|
+
try:
|
|
64
|
+
with open(Path(rules_file).resolve(), "r") as f:
|
|
65
|
+
rule.extend(f.read().splitlines())
|
|
66
|
+
except FileNotFoundError:
|
|
67
|
+
print(f"[yellow]rules file not found at {rules_file}[/yellow]")
|
|
68
|
+
|
|
69
|
+
BaseClass = MailWorker
|
|
70
|
+
if computer_use:
|
|
71
|
+
raise ValueError("computer use is not yet supported for the mail agent")
|
|
72
|
+
else:
|
|
73
|
+
llm_adapter = OpenAIResponsesAdapter(model=model)
|
|
74
|
+
|
|
75
|
+
class CustomMailbot(BaseClass):
|
|
76
|
+
def __init__(self):
|
|
77
|
+
super().__init__(
|
|
78
|
+
llm_adapter=llm_adapter,
|
|
79
|
+
name=agent_name,
|
|
80
|
+
requires=requirements,
|
|
81
|
+
toolkits=toolkits,
|
|
82
|
+
queue=queue,
|
|
83
|
+
rules=rule if len(rule) > 0 else None,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
async def start(self, *, room: RoomClient):
|
|
87
|
+
print(
|
|
88
|
+
"[bold green]Configure and send an email interact with your mailbot[/bold green]"
|
|
89
|
+
)
|
|
90
|
+
return await super().start(room=room)
|
|
91
|
+
|
|
92
|
+
async def get_thread_toolkits(self, *, thread_context):
|
|
93
|
+
toolkits = await super().get_thread_toolkits(thread_context=thread_context)
|
|
94
|
+
|
|
95
|
+
thread_toolkit = Toolkit(name="thread_toolkit", tools=[])
|
|
96
|
+
|
|
97
|
+
if local_shell:
|
|
98
|
+
thread_toolkit.tools.append(
|
|
99
|
+
LocalShellTool(thread_context=thread_context)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if image_generation is not None:
|
|
103
|
+
print("adding openai image gen to thread", flush=True)
|
|
104
|
+
thread_toolkit.tools.append(
|
|
105
|
+
ImageGenerationTool(
|
|
106
|
+
model=image_generation,
|
|
107
|
+
thread_context=thread_context,
|
|
108
|
+
partial_images=3,
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if web_search:
|
|
113
|
+
thread_toolkit.tools.append(WebSearchTool())
|
|
114
|
+
|
|
115
|
+
toolkits.append(thread_toolkit)
|
|
116
|
+
return toolkits
|
|
117
|
+
|
|
118
|
+
return CustomMailbot
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@app.async_command("join")
|
|
122
|
+
async def make_call(
|
|
123
|
+
*,
|
|
124
|
+
project_id: ProjectIdOption = None,
|
|
125
|
+
room: RoomOption,
|
|
126
|
+
role: str = "agent",
|
|
127
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
128
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
129
|
+
rules_file: Optional[str] = None,
|
|
130
|
+
toolkit: Annotated[
|
|
131
|
+
List[str],
|
|
132
|
+
typer.Option("--toolkit", "-t", help="the name or url of a required toolkit"),
|
|
133
|
+
] = [],
|
|
134
|
+
schema: Annotated[
|
|
135
|
+
List[str],
|
|
136
|
+
typer.Option("--schema", "-s", help="the name or url of a required schema"),
|
|
137
|
+
] = [],
|
|
138
|
+
model: Annotated[
|
|
139
|
+
str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
|
|
140
|
+
] = "gpt-5",
|
|
141
|
+
local_shell: Annotated[
|
|
142
|
+
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
143
|
+
] = False,
|
|
144
|
+
web_search: Annotated[
|
|
145
|
+
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
146
|
+
] = False,
|
|
147
|
+
key: Annotated[
|
|
148
|
+
str,
|
|
149
|
+
typer.Option("--key", help="an api key to sign the token with"),
|
|
150
|
+
] = None,
|
|
151
|
+
queue: Annotated[str, typer.Option(..., help="the name of the mail queue")],
|
|
152
|
+
):
|
|
153
|
+
key = await resolve_key(project_id=project_id, key=key)
|
|
154
|
+
|
|
155
|
+
account_client = await get_client()
|
|
156
|
+
try:
|
|
157
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
158
|
+
|
|
159
|
+
room = resolve_room(room)
|
|
160
|
+
|
|
161
|
+
token = ParticipantToken(
|
|
162
|
+
name=agent_name,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
token.add_api_grant(ApiScope.agent_default())
|
|
166
|
+
|
|
167
|
+
token.add_role_grant(role=role)
|
|
168
|
+
token.add_room_grant(room)
|
|
169
|
+
|
|
170
|
+
jwt = token.to_jwt(api_key=key)
|
|
171
|
+
|
|
172
|
+
print("[bold green]Connecting to room...[/bold green]", flush=True)
|
|
173
|
+
async with RoomClient(
|
|
174
|
+
protocol=WebSocketClientProtocol(
|
|
175
|
+
url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
|
|
176
|
+
token=jwt,
|
|
177
|
+
)
|
|
178
|
+
) as client:
|
|
179
|
+
requirements = []
|
|
180
|
+
|
|
181
|
+
for t in toolkit:
|
|
182
|
+
requirements.append(RequiredToolkit(name=t))
|
|
183
|
+
|
|
184
|
+
for t in schema:
|
|
185
|
+
requirements.append(RequiredSchema(name=t))
|
|
186
|
+
|
|
187
|
+
CustomMailbot = build_mailbot(
|
|
188
|
+
computer_use=None,
|
|
189
|
+
model=model,
|
|
190
|
+
local_shell=local_shell,
|
|
191
|
+
agent_name=agent_name,
|
|
192
|
+
rule=rule,
|
|
193
|
+
toolkit=toolkit,
|
|
194
|
+
schema=schema,
|
|
195
|
+
image_generation=None,
|
|
196
|
+
web_search=web_search,
|
|
197
|
+
rules_file=rules_file,
|
|
198
|
+
queue=queue,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
bot = CustomMailbot()
|
|
202
|
+
|
|
203
|
+
await bot.start(room=client)
|
|
204
|
+
try:
|
|
205
|
+
print(
|
|
206
|
+
flush=True,
|
|
207
|
+
)
|
|
208
|
+
await client.protocol.wait_for_close()
|
|
209
|
+
except KeyboardInterrupt:
|
|
210
|
+
await bot.stop()
|
|
211
|
+
|
|
212
|
+
finally:
|
|
213
|
+
await account_client.close()
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@app.async_command("service")
|
|
217
|
+
async def service(
|
|
218
|
+
*,
|
|
219
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
220
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
221
|
+
rules_file: Optional[str] = None,
|
|
222
|
+
toolkit: Annotated[
|
|
223
|
+
List[str],
|
|
224
|
+
typer.Option("--toolkit", "-t", help="the name or url of a required toolkit"),
|
|
225
|
+
] = [],
|
|
226
|
+
schema: Annotated[
|
|
227
|
+
List[str],
|
|
228
|
+
typer.Option("--schema", "-s", help="the name or url of a required schema"),
|
|
229
|
+
] = [],
|
|
230
|
+
model: Annotated[
|
|
231
|
+
str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
|
|
232
|
+
] = "gpt-5",
|
|
233
|
+
local_shell: Annotated[
|
|
234
|
+
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
235
|
+
] = False,
|
|
236
|
+
host: Annotated[Optional[str], typer.Option()] = None,
|
|
237
|
+
port: Annotated[Optional[int], typer.Option()] = None,
|
|
238
|
+
path: Annotated[str, typer.Option()] = "/agent",
|
|
239
|
+
queue: Annotated[str, typer.Option(..., help="the name of the mail queue")],
|
|
240
|
+
):
|
|
241
|
+
print("[bold green]Connecting to room...[/bold green]", flush=True)
|
|
242
|
+
|
|
243
|
+
service = ServiceHost(host=host, port=port)
|
|
244
|
+
service.add_path(
|
|
245
|
+
path=path,
|
|
246
|
+
cls=build_mailbot(
|
|
247
|
+
queue=queue,
|
|
248
|
+
computer_use=None,
|
|
249
|
+
model=model,
|
|
250
|
+
local_shell=local_shell,
|
|
251
|
+
agent_name=agent_name,
|
|
252
|
+
rule=rule,
|
|
253
|
+
toolkit=toolkit,
|
|
254
|
+
schema=schema,
|
|
255
|
+
image_generation=None,
|
|
256
|
+
rules_file=rules_file,
|
|
257
|
+
),
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
await service.run()
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from rich import print
|
|
3
|
+
from typing import Annotated, Optional
|
|
4
|
+
from meshagent.cli.common_options import ProjectIdOption, RoomOption
|
|
5
|
+
from meshagent.api import RoomClient, WebSocketClientProtocol, RoomException
|
|
6
|
+
from meshagent.api.helpers import meshagent_base_url, websocket_room_url
|
|
7
|
+
from meshagent.cli import async_typer
|
|
8
|
+
from meshagent.api import ParticipantToken, ApiScope
|
|
9
|
+
from meshagent.cli.helper import (
|
|
10
|
+
get_client,
|
|
11
|
+
resolve_project_id,
|
|
12
|
+
resolve_room,
|
|
13
|
+
resolve_key,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from meshagent.api import RequiredSchema
|
|
17
|
+
from meshagent.api.services import ServiceHost
|
|
18
|
+
|
|
19
|
+
app = async_typer.AsyncTyper(help="Join a meeting transcriber to a room")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command("join")
|
|
23
|
+
async def join(
|
|
24
|
+
*,
|
|
25
|
+
project_id: ProjectIdOption = None,
|
|
26
|
+
room: RoomOption,
|
|
27
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent")],
|
|
28
|
+
key: Annotated[
|
|
29
|
+
str,
|
|
30
|
+
typer.Option("--key", help="an api key to sign the token with"),
|
|
31
|
+
] = None,
|
|
32
|
+
):
|
|
33
|
+
try:
|
|
34
|
+
from meshagent.livekit.agents.meeting_transcriber import MeetingTranscriber
|
|
35
|
+
except ImportError:
|
|
36
|
+
|
|
37
|
+
class MeetingTranscriber:
|
|
38
|
+
def __init__(self, **kwargs):
|
|
39
|
+
raise RoomException(
|
|
40
|
+
"meshagent.livekit module not found, transcribers are not available"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
key = await resolve_key(project_id=project_id, key=key)
|
|
44
|
+
|
|
45
|
+
account_client = await get_client()
|
|
46
|
+
try:
|
|
47
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
48
|
+
room = resolve_room(room)
|
|
49
|
+
|
|
50
|
+
token = ParticipantToken(
|
|
51
|
+
name=agent_name,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
token.add_api_grant(ApiScope.agent_default())
|
|
55
|
+
|
|
56
|
+
token.add_role_grant(role="agent")
|
|
57
|
+
token.add_room_grant(room)
|
|
58
|
+
|
|
59
|
+
jwt = token.to_jwt(api_key=key)
|
|
60
|
+
|
|
61
|
+
print("[bold green]Connecting to room...[/bold green]", flush=True)
|
|
62
|
+
async with RoomClient(
|
|
63
|
+
protocol=WebSocketClientProtocol(
|
|
64
|
+
url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
|
|
65
|
+
token=jwt,
|
|
66
|
+
)
|
|
67
|
+
) as client:
|
|
68
|
+
requirements = []
|
|
69
|
+
|
|
70
|
+
requirements.append(RequiredSchema(name="transcript"))
|
|
71
|
+
|
|
72
|
+
bot = MeetingTranscriber(
|
|
73
|
+
name=agent_name,
|
|
74
|
+
requires=requirements,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
await bot.start(room=client)
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
print(
|
|
81
|
+
f"[bold green]Open the studio to interact with your agent: {meshagent_base_url().replace('api.', 'studio.')}/projects/{project_id}/rooms/{client.room_name}[/bold green]",
|
|
82
|
+
flush=True,
|
|
83
|
+
)
|
|
84
|
+
await client.protocol.wait_for_close()
|
|
85
|
+
except KeyboardInterrupt:
|
|
86
|
+
await bot.stop()
|
|
87
|
+
|
|
88
|
+
finally:
|
|
89
|
+
await account_client.close()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@app.async_command("service")
|
|
93
|
+
async def service(
|
|
94
|
+
*,
|
|
95
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent")],
|
|
96
|
+
host: Annotated[Optional[str], typer.Option()] = None,
|
|
97
|
+
port: Annotated[Optional[int], typer.Option()] = None,
|
|
98
|
+
path: Annotated[str, typer.Option()] = "/agent",
|
|
99
|
+
):
|
|
100
|
+
try:
|
|
101
|
+
from meshagent.livekit.agents.meeting_transcriber import MeetingTranscriber
|
|
102
|
+
except ImportError:
|
|
103
|
+
|
|
104
|
+
class MeetingTranscriber:
|
|
105
|
+
def __init__(self, **kwargs):
|
|
106
|
+
raise RoomException(
|
|
107
|
+
"meshagent.livekit module not found, voicebots are not available"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
requirements = []
|
|
111
|
+
|
|
112
|
+
requirements.append(RequiredSchema(name="transcript"))
|
|
113
|
+
|
|
114
|
+
service = ServiceHost(host=host, port=port)
|
|
115
|
+
|
|
116
|
+
@service.path(path=path)
|
|
117
|
+
class CustomMeetingTranscriber(MeetingTranscriber):
|
|
118
|
+
def __init__(self):
|
|
119
|
+
super().__init__(
|
|
120
|
+
name=agent_name,
|
|
121
|
+
requires=requirements,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
await service.run()
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from rich import print
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
from meshagent.cli.common_options import (
|
|
5
|
+
ProjectIdOption,
|
|
6
|
+
RoomOption,
|
|
7
|
+
)
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
from meshagent.api import RoomClient, WebSocketClientProtocol
|
|
11
|
+
from meshagent.api.helpers import meshagent_base_url, websocket_room_url
|
|
12
|
+
from meshagent.cli import async_typer
|
|
13
|
+
from meshagent.cli.helper import (
|
|
14
|
+
get_client,
|
|
15
|
+
resolve_project_id,
|
|
16
|
+
resolve_room,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
app = async_typer.AsyncTyper()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command("list-participants")
|
|
23
|
+
async def messaging_list_participants_command(
|
|
24
|
+
*,
|
|
25
|
+
project_id: ProjectIdOption = None,
|
|
26
|
+
room: RoomOption,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
List all messaging-enabled participants in the room.
|
|
30
|
+
"""
|
|
31
|
+
account_client = await get_client()
|
|
32
|
+
try:
|
|
33
|
+
# Resolve project_id if not provided
|
|
34
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
35
|
+
|
|
36
|
+
room = resolve_room(room)
|
|
37
|
+
|
|
38
|
+
connection = await account_client.connect_room(project_id=project_id, room=room)
|
|
39
|
+
|
|
40
|
+
print("[bold green]Connecting to room...[/bold green]")
|
|
41
|
+
async with RoomClient(
|
|
42
|
+
protocol=WebSocketClientProtocol(
|
|
43
|
+
url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
|
|
44
|
+
token=connection.jwt,
|
|
45
|
+
)
|
|
46
|
+
) as client:
|
|
47
|
+
# Must enable before we can see who else is enabled
|
|
48
|
+
await client.messaging.enable()
|
|
49
|
+
await client.messaging.start()
|
|
50
|
+
|
|
51
|
+
participants = client.messaging.get_participants()
|
|
52
|
+
output = []
|
|
53
|
+
for p in participants:
|
|
54
|
+
output.append({"id": p.id, "role": p.role, "attributes": p._attributes})
|
|
55
|
+
|
|
56
|
+
print(json.dumps(output, indent=2))
|
|
57
|
+
|
|
58
|
+
await client.messaging.stop()
|
|
59
|
+
|
|
60
|
+
finally:
|
|
61
|
+
await account_client.close()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@app.async_command("send")
|
|
65
|
+
async def messaging_send_command(
|
|
66
|
+
*,
|
|
67
|
+
project_id: ProjectIdOption = None,
|
|
68
|
+
room: RoomOption,
|
|
69
|
+
to_participant_id: Annotated[
|
|
70
|
+
str, typer.Option(..., help="Participant ID to send a message to")
|
|
71
|
+
],
|
|
72
|
+
type: Annotated[str, typer.Option(..., help="type of the message to send")],
|
|
73
|
+
data: Annotated[str, typer.Option(..., help="JSON message to send")],
|
|
74
|
+
):
|
|
75
|
+
"""
|
|
76
|
+
Send a direct message to a single participant in the room.
|
|
77
|
+
"""
|
|
78
|
+
account_client = await get_client()
|
|
79
|
+
try:
|
|
80
|
+
# Resolve project_id if not provided
|
|
81
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
82
|
+
room = resolve_room(room)
|
|
83
|
+
|
|
84
|
+
connection = await account_client.connect_room(project_id=project_id, room=room)
|
|
85
|
+
|
|
86
|
+
print("[bold green]Connecting to room...[/bold green]")
|
|
87
|
+
async with RoomClient(
|
|
88
|
+
protocol=WebSocketClientProtocol(
|
|
89
|
+
url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
|
|
90
|
+
token=connection.jwt,
|
|
91
|
+
)
|
|
92
|
+
) as client:
|
|
93
|
+
# Create and enable messaging
|
|
94
|
+
await client.messaging.enable()
|
|
95
|
+
await client.messaging.start()
|
|
96
|
+
|
|
97
|
+
# Find the participant we want to message
|
|
98
|
+
participant = None
|
|
99
|
+
for p in client.messaging.get_participants():
|
|
100
|
+
if p.id == to_participant_id:
|
|
101
|
+
participant = p
|
|
102
|
+
break
|
|
103
|
+
|
|
104
|
+
if participant is None:
|
|
105
|
+
print(
|
|
106
|
+
f"[bold red]Participant with ID {to_participant_id} not found or not messaging-enabled.[/bold red]"
|
|
107
|
+
)
|
|
108
|
+
else:
|
|
109
|
+
# Send the message
|
|
110
|
+
await client.messaging.send_message(
|
|
111
|
+
to=participant,
|
|
112
|
+
type=type,
|
|
113
|
+
message=json.loads(data),
|
|
114
|
+
attachment=None,
|
|
115
|
+
)
|
|
116
|
+
print("[bold cyan]Message sent successfully.[/bold cyan]")
|
|
117
|
+
|
|
118
|
+
await client.messaging.stop()
|
|
119
|
+
finally:
|
|
120
|
+
await account_client.close()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@app.async_command("broadcast")
|
|
124
|
+
async def messaging_broadcast_command(
|
|
125
|
+
*,
|
|
126
|
+
project_id: ProjectIdOption = None,
|
|
127
|
+
room: RoomOption,
|
|
128
|
+
data: Annotated[str, typer.Option(..., help="JSON message to broadcast")],
|
|
129
|
+
):
|
|
130
|
+
"""
|
|
131
|
+
Broadcast a message to all messaging-enabled participants in the room.
|
|
132
|
+
"""
|
|
133
|
+
account_client = await get_client()
|
|
134
|
+
try:
|
|
135
|
+
# Resolve project_id if not provided
|
|
136
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
137
|
+
|
|
138
|
+
room = resolve_room(room)
|
|
139
|
+
connection = await account_client.connect_room(project_id=project_id, room=room)
|
|
140
|
+
|
|
141
|
+
print("[bold green]Connecting to room...[/bold green]")
|
|
142
|
+
async with RoomClient(
|
|
143
|
+
protocol=WebSocketClientProtocol(
|
|
144
|
+
url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
|
|
145
|
+
token=connection.jwt,
|
|
146
|
+
)
|
|
147
|
+
) as client:
|
|
148
|
+
# Create and enable messaging
|
|
149
|
+
await client.messaging.enable()
|
|
150
|
+
await client.messaging.start()
|
|
151
|
+
|
|
152
|
+
# Broadcast the message
|
|
153
|
+
await client.messaging.broadcast_message(
|
|
154
|
+
type="chat.broadcast", message=json.loads(data), attachment=None
|
|
155
|
+
)
|
|
156
|
+
print("[bold cyan]Broadcast message sent successfully.[/bold cyan]")
|
|
157
|
+
|
|
158
|
+
await client.messaging.stop()
|
|
159
|
+
finally:
|
|
160
|
+
await account_client.close()
|