meshagent-cli 0.7.0__py3-none-any.whl → 0.21.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meshagent/cli/agent.py +15 -11
- meshagent/cli/api_keys.py +4 -4
- meshagent/cli/async_typer.py +52 -4
- meshagent/cli/call.py +12 -8
- meshagent/cli/chatbot.py +1007 -129
- meshagent/cli/cli.py +21 -20
- meshagent/cli/cli_mcp.py +92 -28
- meshagent/cli/cli_secrets.py +10 -10
- meshagent/cli/common_options.py +19 -4
- meshagent/cli/containers.py +164 -16
- meshagent/cli/database.py +997 -0
- meshagent/cli/developer.py +3 -3
- meshagent/cli/exec.py +22 -6
- meshagent/cli/helper.py +62 -11
- meshagent/cli/helpers.py +66 -9
- meshagent/cli/host.py +37 -0
- meshagent/cli/mailbot.py +1004 -40
- meshagent/cli/mailboxes.py +223 -0
- meshagent/cli/meeting_transcriber.py +10 -4
- meshagent/cli/messaging.py +7 -7
- meshagent/cli/multi.py +402 -0
- meshagent/cli/oauth2.py +44 -21
- meshagent/cli/participant_token.py +5 -3
- meshagent/cli/port.py +70 -0
- meshagent/cli/queue.py +2 -2
- meshagent/cli/room.py +20 -212
- meshagent/cli/rooms.py +214 -0
- meshagent/cli/services.py +32 -23
- meshagent/cli/sessions.py +5 -5
- meshagent/cli/storage.py +5 -5
- meshagent/cli/task_runner.py +770 -0
- meshagent/cli/version.py +1 -1
- meshagent/cli/voicebot.py +502 -76
- meshagent/cli/webhook.py +7 -7
- meshagent/cli/worker.py +1327 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/METADATA +13 -13
- meshagent_cli-0.21.0.dist-info/RECORD +44 -0
- meshagent_cli-0.7.0.dist-info/RECORD +0 -36
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/WHEEL +0 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/entry_points.txt +0 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/top_level.txt +0 -0
meshagent/cli/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.21.0"
|
meshagent/cli/voicebot.py
CHANGED
|
@@ -5,56 +5,200 @@ from meshagent.cli.common_options import ProjectIdOption, RoomOption
|
|
|
5
5
|
from meshagent.api import RoomClient, WebSocketClientProtocol, RoomException
|
|
6
6
|
from meshagent.api.helpers import meshagent_base_url, websocket_room_url
|
|
7
7
|
from meshagent.cli import async_typer
|
|
8
|
-
from meshagent.api import ParticipantToken, ApiScope
|
|
8
|
+
from meshagent.api import ParticipantToken, ApiScope, RemoteParticipant
|
|
9
9
|
from meshagent.cli.helper import (
|
|
10
10
|
get_client,
|
|
11
11
|
resolve_project_id,
|
|
12
12
|
resolve_room,
|
|
13
13
|
resolve_key,
|
|
14
|
+
cleanup_args,
|
|
14
15
|
)
|
|
15
16
|
from typing import List
|
|
16
|
-
|
|
17
17
|
from meshagent.api import RequiredToolkit, RequiredSchema
|
|
18
|
-
from meshagent.api.services import ServiceHost
|
|
19
18
|
from pathlib import Path
|
|
19
|
+
from meshagent.agents.config import RulesConfig
|
|
20
|
+
import logging
|
|
21
|
+
|
|
22
|
+
from meshagent.cli.host import get_service, run_services, get_deferred, service_specs
|
|
23
|
+
from meshagent.api.specs.service import AgentSpec, ANNOTATION_AGENT_TYPE
|
|
24
|
+
|
|
25
|
+
import yaml
|
|
20
26
|
|
|
27
|
+
import shlex
|
|
28
|
+
import sys
|
|
29
|
+
|
|
30
|
+
from meshagent.api.client import ConflictError
|
|
21
31
|
|
|
22
32
|
app = async_typer.AsyncTyper(help="Join a voicebot to a room")
|
|
23
33
|
|
|
34
|
+
logger = logging.getLogger("voicebot")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def build_voicebot(
|
|
38
|
+
*,
|
|
39
|
+
agent_name: str,
|
|
40
|
+
rules: list[str],
|
|
41
|
+
rules_file: Optional[str] = None,
|
|
42
|
+
toolkits: list[str],
|
|
43
|
+
schemas: list[str],
|
|
44
|
+
auto_greet_message: Optional[str] = None,
|
|
45
|
+
auto_greet_prompt: Optional[str] = None,
|
|
46
|
+
room_rules_paths: list[str],
|
|
47
|
+
):
|
|
48
|
+
requirements = []
|
|
49
|
+
|
|
50
|
+
for t in toolkits:
|
|
51
|
+
requirements.append(RequiredToolkit(name=t))
|
|
52
|
+
|
|
53
|
+
for t in schemas:
|
|
54
|
+
requirements.append(RequiredSchema(name=t))
|
|
55
|
+
|
|
56
|
+
if rules_file is not None:
|
|
57
|
+
try:
|
|
58
|
+
with open(Path(rules_file).resolve(), "r") as f:
|
|
59
|
+
rules.extend(f.read().splitlines())
|
|
60
|
+
except FileNotFoundError:
|
|
61
|
+
print(f"[yellow]rules file not found at {rules_file}[/yellow]")
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
from meshagent.livekit.agents.voice import VoiceBot
|
|
65
|
+
except ImportError:
|
|
66
|
+
|
|
67
|
+
class VoiceBot:
|
|
68
|
+
def __init__(self, **kwargs):
|
|
69
|
+
raise RoomException(
|
|
70
|
+
"meshagent.livekit module not found, voicebots are not available"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
class CustomVoiceBot(VoiceBot):
|
|
74
|
+
def __init__(self):
|
|
75
|
+
super().__init__(
|
|
76
|
+
auto_greet_message=auto_greet_message,
|
|
77
|
+
auto_greet_prompt=auto_greet_prompt,
|
|
78
|
+
name=agent_name,
|
|
79
|
+
requires=requirements,
|
|
80
|
+
rules=rules if len(rules) > 0 else None,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
async def start(self, *, room: RoomClient):
|
|
84
|
+
await super().start(room=room)
|
|
85
|
+
|
|
86
|
+
if room_rules_paths is not None:
|
|
87
|
+
for p in room_rules_paths:
|
|
88
|
+
await self._load_room_rules(path=p)
|
|
89
|
+
|
|
90
|
+
async def _load_room_rules(
|
|
91
|
+
self,
|
|
92
|
+
*,
|
|
93
|
+
path: str,
|
|
94
|
+
participant: Optional[RemoteParticipant] = None,
|
|
95
|
+
):
|
|
96
|
+
rules = []
|
|
97
|
+
try:
|
|
98
|
+
room_rules = await self.room.storage.download(path=path)
|
|
99
|
+
|
|
100
|
+
rules_txt = room_rules.data.decode()
|
|
101
|
+
|
|
102
|
+
rules_config = RulesConfig.parse(rules_txt)
|
|
103
|
+
|
|
104
|
+
if rules_config.rules is not None:
|
|
105
|
+
rules.extend(rules_config.rules)
|
|
106
|
+
|
|
107
|
+
if participant is not None:
|
|
108
|
+
client = participant.get_attribute("client")
|
|
109
|
+
|
|
110
|
+
if rules_config.client_rules is not None and client is not None:
|
|
111
|
+
cr = rules_config.client_rules.get(client)
|
|
112
|
+
if cr is not None:
|
|
113
|
+
rules.extend(cr)
|
|
114
|
+
|
|
115
|
+
except RoomException:
|
|
116
|
+
try:
|
|
117
|
+
logger.info("attempting to initialize rules file")
|
|
118
|
+
handle = await self.room.storage.open(path=path, overwrite=False)
|
|
119
|
+
await self.room.storage.write(
|
|
120
|
+
handle=handle,
|
|
121
|
+
data="# Add rules to this file to customize your agent's behavior, lines starting with # will be ignored.\n\n".encode(),
|
|
122
|
+
)
|
|
123
|
+
await self.room.storage.close(handle=handle)
|
|
124
|
+
|
|
125
|
+
except RoomException:
|
|
126
|
+
pass
|
|
127
|
+
logger.info(
|
|
128
|
+
f"unable to load rules from {path}, continuing with default rules"
|
|
129
|
+
)
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
return rules
|
|
133
|
+
|
|
134
|
+
async def get_rules(self, *, participant: RemoteParticipant):
|
|
135
|
+
rules = [*self.rules] if self.rules is not None else []
|
|
136
|
+
if room_rules_paths is not None:
|
|
137
|
+
for p in room_rules_paths:
|
|
138
|
+
rules.extend(
|
|
139
|
+
await self._load_room_rules(participant=participant, path=p)
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
logger.info(f"voicebot using rules {rules}")
|
|
143
|
+
|
|
144
|
+
return rules
|
|
145
|
+
|
|
146
|
+
return CustomVoiceBot
|
|
147
|
+
|
|
24
148
|
|
|
25
149
|
@app.async_command("join")
|
|
26
150
|
async def make_call(
|
|
27
151
|
*,
|
|
28
|
-
project_id: ProjectIdOption
|
|
152
|
+
project_id: ProjectIdOption,
|
|
29
153
|
room: RoomOption,
|
|
30
154
|
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
31
155
|
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
32
156
|
rules_file: Optional[str] = None,
|
|
157
|
+
require_toolkit: Annotated[
|
|
158
|
+
List[str],
|
|
159
|
+
typer.Option(
|
|
160
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
161
|
+
),
|
|
162
|
+
] = [],
|
|
163
|
+
require_schema: Annotated[
|
|
164
|
+
List[str],
|
|
165
|
+
typer.Option(
|
|
166
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
167
|
+
),
|
|
168
|
+
] = [],
|
|
33
169
|
toolkit: Annotated[
|
|
34
170
|
List[str],
|
|
35
|
-
typer.Option(
|
|
171
|
+
typer.Option(
|
|
172
|
+
"--toolkit", "-t", help="the name or url of a required toolkit", hidden=True
|
|
173
|
+
),
|
|
36
174
|
] = [],
|
|
37
175
|
schema: Annotated[
|
|
38
176
|
List[str],
|
|
39
|
-
typer.Option(
|
|
177
|
+
typer.Option(
|
|
178
|
+
"--schema", "-s", help="the name or url of a required schema", hidden=True
|
|
179
|
+
),
|
|
40
180
|
] = [],
|
|
41
|
-
auto_greet_message: Annotated[
|
|
42
|
-
|
|
181
|
+
auto_greet_message: Annotated[
|
|
182
|
+
Optional[str],
|
|
183
|
+
typer.Option(help="Message to send automatically when the bot joins"),
|
|
184
|
+
] = None,
|
|
185
|
+
auto_greet_prompt: Annotated[
|
|
186
|
+
Optional[str],
|
|
187
|
+
typer.Option(help="Prompt to generate an auto-greet message"),
|
|
188
|
+
] = None,
|
|
43
189
|
key: Annotated[
|
|
44
190
|
str,
|
|
45
191
|
typer.Option("--key", help="an api key to sign the token with"),
|
|
46
192
|
] = None,
|
|
193
|
+
room_rules: Annotated[
|
|
194
|
+
List[str],
|
|
195
|
+
typer.Option(
|
|
196
|
+
"--room-rules",
|
|
197
|
+
"-rr",
|
|
198
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
199
|
+
),
|
|
200
|
+
] = [],
|
|
47
201
|
):
|
|
48
|
-
try:
|
|
49
|
-
from meshagent.livekit.agents.voice import VoiceBot
|
|
50
|
-
except ImportError:
|
|
51
|
-
|
|
52
|
-
class VoiceBot:
|
|
53
|
-
def __init__(self, **kwargs):
|
|
54
|
-
raise RoomException(
|
|
55
|
-
"meshagent.livekit module not found, voicebots are not available"
|
|
56
|
-
)
|
|
57
|
-
|
|
58
202
|
key = await resolve_key(project_id=project_id, key=key)
|
|
59
203
|
|
|
60
204
|
account_client = await get_client()
|
|
@@ -71,13 +215,18 @@ async def make_call(
|
|
|
71
215
|
token.add_role_grant(role="agent")
|
|
72
216
|
token.add_room_grant(room)
|
|
73
217
|
|
|
218
|
+
CustomVoiceBot = build_voicebot(
|
|
219
|
+
agent_name=agent_name,
|
|
220
|
+
rules=rule,
|
|
221
|
+
rules_file=rules_file,
|
|
222
|
+
toolkits=require_toolkit + toolkit,
|
|
223
|
+
schemas=require_schema + schema,
|
|
224
|
+
auto_greet_message=auto_greet_message,
|
|
225
|
+
auto_greet_prompt=auto_greet_prompt,
|
|
226
|
+
room_rules_paths=room_rules,
|
|
227
|
+
)
|
|
228
|
+
|
|
74
229
|
jwt = token.to_jwt(api_key=key)
|
|
75
|
-
if rules_file is not None:
|
|
76
|
-
try:
|
|
77
|
-
with open(Path(rules_file).resolve(), "r") as f:
|
|
78
|
-
rule.extend(f.read().splitlines())
|
|
79
|
-
except FileNotFoundError:
|
|
80
|
-
print(f"[yellow]rules file not found at {rules_file}[/yellow]")
|
|
81
230
|
|
|
82
231
|
print("[bold green]Connecting to room...[/bold green]", flush=True)
|
|
83
232
|
async with RoomClient(
|
|
@@ -86,21 +235,7 @@ async def make_call(
|
|
|
86
235
|
token=jwt,
|
|
87
236
|
)
|
|
88
237
|
) as client:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
for t in toolkit:
|
|
92
|
-
requirements.append(RequiredToolkit(name=t))
|
|
93
|
-
|
|
94
|
-
for t in schema:
|
|
95
|
-
requirements.append(RequiredSchema(name=t))
|
|
96
|
-
|
|
97
|
-
bot = VoiceBot(
|
|
98
|
-
auto_greet_message=auto_greet_message,
|
|
99
|
-
auto_greet_prompt=auto_greet_prompt,
|
|
100
|
-
name=agent_name,
|
|
101
|
-
requires=requirements,
|
|
102
|
-
rules=rule if len(rule) > 0 else None,
|
|
103
|
-
)
|
|
238
|
+
bot = CustomVoiceBot()
|
|
104
239
|
|
|
105
240
|
await bot.start(room=client)
|
|
106
241
|
|
|
@@ -123,56 +258,347 @@ async def service(
|
|
|
123
258
|
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
124
259
|
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
125
260
|
rules_file: Optional[str] = None,
|
|
261
|
+
require_toolkit: Annotated[
|
|
262
|
+
List[str],
|
|
263
|
+
typer.Option(
|
|
264
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
265
|
+
),
|
|
266
|
+
] = [],
|
|
267
|
+
require_schema: Annotated[
|
|
268
|
+
List[str],
|
|
269
|
+
typer.Option(
|
|
270
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
271
|
+
),
|
|
272
|
+
] = [],
|
|
273
|
+
toolkit: Annotated[
|
|
274
|
+
List[str],
|
|
275
|
+
typer.Option(
|
|
276
|
+
"--toolkit", "-t", help="the name or url of a required toolkit", hidden=True
|
|
277
|
+
),
|
|
278
|
+
] = [],
|
|
279
|
+
schema: Annotated[
|
|
280
|
+
List[str],
|
|
281
|
+
typer.Option(
|
|
282
|
+
"--schema", "-s", help="the name or url of a required schema", hidden=True
|
|
283
|
+
),
|
|
284
|
+
] = [],
|
|
285
|
+
auto_greet_message: Annotated[
|
|
286
|
+
Optional[str],
|
|
287
|
+
typer.Option(help="Message to send automatically when the bot joins"),
|
|
288
|
+
] = None,
|
|
289
|
+
auto_greet_prompt: Annotated[
|
|
290
|
+
Optional[str],
|
|
291
|
+
typer.Option(help="Prompt to generate an auto-greet message"),
|
|
292
|
+
] = None,
|
|
293
|
+
host: Annotated[
|
|
294
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
295
|
+
] = None,
|
|
296
|
+
port: Annotated[
|
|
297
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
298
|
+
] = None,
|
|
299
|
+
path: Annotated[
|
|
300
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
301
|
+
] = None,
|
|
302
|
+
room_rules: Annotated[
|
|
303
|
+
List[str],
|
|
304
|
+
typer.Option(
|
|
305
|
+
"--room-rules",
|
|
306
|
+
"-rr",
|
|
307
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
308
|
+
),
|
|
309
|
+
] = [],
|
|
310
|
+
):
|
|
311
|
+
CustomVoiceBot = build_voicebot(
|
|
312
|
+
agent_name=agent_name,
|
|
313
|
+
rules=rule,
|
|
314
|
+
rules_file=rules_file,
|
|
315
|
+
toolkits=require_toolkit + toolkit,
|
|
316
|
+
schemas=require_schema + schema,
|
|
317
|
+
auto_greet_message=auto_greet_message,
|
|
318
|
+
auto_greet_prompt=auto_greet_prompt,
|
|
319
|
+
room_rules_paths=room_rules,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
service = get_service(host=host, port=port)
|
|
323
|
+
|
|
324
|
+
service.agents.append(
|
|
325
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "ChatBot"})
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
if path is None:
|
|
329
|
+
path = "/agent"
|
|
330
|
+
i = 0
|
|
331
|
+
while service.has_path(path):
|
|
332
|
+
i += 1
|
|
333
|
+
path = f"/agent{i}"
|
|
334
|
+
|
|
335
|
+
service.add_path(identity=agent_name, path=path, cls=CustomVoiceBot)
|
|
336
|
+
|
|
337
|
+
if not get_deferred():
|
|
338
|
+
await run_services()
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
@app.async_command("spec")
|
|
342
|
+
async def spec(
|
|
343
|
+
*,
|
|
344
|
+
service_name: Annotated[str, typer.Option("--service-name", help="service name")],
|
|
345
|
+
service_description: Annotated[
|
|
346
|
+
Optional[str], typer.Option("--service-description", help="service description")
|
|
347
|
+
] = None,
|
|
348
|
+
service_title: Annotated[
|
|
349
|
+
Optional[str],
|
|
350
|
+
typer.Option("--service-title", help="a display name for the service"),
|
|
351
|
+
] = None,
|
|
352
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
353
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
354
|
+
rules_file: Optional[str] = None,
|
|
355
|
+
require_toolkit: Annotated[
|
|
356
|
+
List[str],
|
|
357
|
+
typer.Option(
|
|
358
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
359
|
+
),
|
|
360
|
+
] = [],
|
|
361
|
+
require_schema: Annotated[
|
|
362
|
+
List[str],
|
|
363
|
+
typer.Option(
|
|
364
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
365
|
+
),
|
|
366
|
+
] = [],
|
|
126
367
|
toolkit: Annotated[
|
|
127
368
|
List[str],
|
|
128
|
-
typer.Option(
|
|
369
|
+
typer.Option(
|
|
370
|
+
"--toolkit", "-t", help="the name or url of a required toolkit", hidden=True
|
|
371
|
+
),
|
|
129
372
|
] = [],
|
|
130
373
|
schema: Annotated[
|
|
131
374
|
List[str],
|
|
132
|
-
typer.Option(
|
|
375
|
+
typer.Option(
|
|
376
|
+
"--schema", "-s", help="the name or url of a required schema", hidden=True
|
|
377
|
+
),
|
|
378
|
+
] = [],
|
|
379
|
+
auto_greet_message: Annotated[
|
|
380
|
+
Optional[str],
|
|
381
|
+
typer.Option(help="Message to send automatically when the bot joins"),
|
|
382
|
+
] = None,
|
|
383
|
+
auto_greet_prompt: Annotated[
|
|
384
|
+
Optional[str],
|
|
385
|
+
typer.Option(help="Prompt to generate an auto-greet message"),
|
|
386
|
+
] = None,
|
|
387
|
+
host: Annotated[
|
|
388
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
389
|
+
] = None,
|
|
390
|
+
port: Annotated[
|
|
391
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
392
|
+
] = None,
|
|
393
|
+
path: Annotated[
|
|
394
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
395
|
+
] = None,
|
|
396
|
+
room_rules: Annotated[
|
|
397
|
+
List[str],
|
|
398
|
+
typer.Option(
|
|
399
|
+
"--room-rules",
|
|
400
|
+
"-rr",
|
|
401
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
402
|
+
),
|
|
133
403
|
] = [],
|
|
134
|
-
auto_greet_message: Annotated[Optional[str], typer.Option()] = None,
|
|
135
|
-
auto_greet_prompt: Annotated[Optional[str], typer.Option()] = None,
|
|
136
|
-
host: Annotated[Optional[str], typer.Option()] = None,
|
|
137
|
-
port: Annotated[Optional[int], typer.Option()] = None,
|
|
138
|
-
path: Annotated[str, typer.Option()] = "/agent",
|
|
139
404
|
):
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
405
|
+
CustomVoiceBot = build_voicebot(
|
|
406
|
+
agent_name=agent_name,
|
|
407
|
+
rules=rule,
|
|
408
|
+
rules_file=rules_file,
|
|
409
|
+
toolkits=require_toolkit + toolkit,
|
|
410
|
+
schemas=require_schema + schema,
|
|
411
|
+
auto_greet_message=auto_greet_message,
|
|
412
|
+
auto_greet_prompt=auto_greet_prompt,
|
|
413
|
+
room_rules_paths=room_rules,
|
|
414
|
+
)
|
|
143
415
|
|
|
144
|
-
|
|
145
|
-
def __init__(self, **kwargs):
|
|
146
|
-
raise RoomException(
|
|
147
|
-
"meshagent.livekit module not found, voicebots are not available"
|
|
148
|
-
)
|
|
416
|
+
service = get_service(host=host, port=port)
|
|
149
417
|
|
|
150
|
-
|
|
418
|
+
service.agents.append(
|
|
419
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "ChatBot"})
|
|
420
|
+
)
|
|
151
421
|
|
|
152
|
-
|
|
153
|
-
|
|
422
|
+
if path is None:
|
|
423
|
+
path = "/agent"
|
|
424
|
+
i = 0
|
|
425
|
+
while service.has_path(path):
|
|
426
|
+
i += 1
|
|
427
|
+
path = f"/agent{i}"
|
|
154
428
|
|
|
155
|
-
|
|
156
|
-
requirements.append(RequiredSchema(name=t))
|
|
429
|
+
service.add_path(identity=agent_name, path=path, cls=CustomVoiceBot)
|
|
157
430
|
|
|
158
|
-
|
|
431
|
+
spec = service_specs()[0]
|
|
432
|
+
spec.metadata.annotations = {
|
|
433
|
+
"meshagent.service.id": service_name,
|
|
434
|
+
}
|
|
435
|
+
spec.metadata.name = service_name
|
|
436
|
+
spec.metadata.description = service_description
|
|
437
|
+
spec.container.image = (
|
|
438
|
+
"us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz"
|
|
439
|
+
)
|
|
440
|
+
spec.container.command = shlex.join(
|
|
441
|
+
["meshagent", "voicebot", "service", *cleanup_args(sys.argv[2:])]
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
print(yaml.dump(spec.model_dump(mode="json", exclude_none=True), sort_keys=False))
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
@app.async_command("deploy")
|
|
448
|
+
async def deploy(
|
|
449
|
+
*,
|
|
450
|
+
service_name: Annotated[str, typer.Option("--service-name", help="service name")],
|
|
451
|
+
service_description: Annotated[
|
|
452
|
+
Optional[str], typer.Option("--service-description", help="service description")
|
|
453
|
+
] = None,
|
|
454
|
+
service_title: Annotated[
|
|
455
|
+
Optional[str],
|
|
456
|
+
typer.Option("--service-title", help="a display name for the service"),
|
|
457
|
+
] = None,
|
|
458
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
459
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
460
|
+
rules_file: Optional[str] = None,
|
|
461
|
+
require_toolkit: Annotated[
|
|
462
|
+
List[str],
|
|
463
|
+
typer.Option(
|
|
464
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
465
|
+
),
|
|
466
|
+
] = [],
|
|
467
|
+
require_schema: Annotated[
|
|
468
|
+
List[str],
|
|
469
|
+
typer.Option(
|
|
470
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
471
|
+
),
|
|
472
|
+
] = [],
|
|
473
|
+
toolkit: Annotated[
|
|
474
|
+
List[str],
|
|
475
|
+
typer.Option(
|
|
476
|
+
"--toolkit", "-t", help="the name or url of a required toolkit", hidden=True
|
|
477
|
+
),
|
|
478
|
+
] = [],
|
|
479
|
+
schema: Annotated[
|
|
480
|
+
List[str],
|
|
481
|
+
typer.Option(
|
|
482
|
+
"--schema", "-s", help="the name or url of a required schema", hidden=True
|
|
483
|
+
),
|
|
484
|
+
] = [],
|
|
485
|
+
auto_greet_message: Annotated[
|
|
486
|
+
Optional[str],
|
|
487
|
+
typer.Option(help="Message to send automatically when the bot joins"),
|
|
488
|
+
] = None,
|
|
489
|
+
auto_greet_prompt: Annotated[
|
|
490
|
+
Optional[str],
|
|
491
|
+
typer.Option(help="Prompt to generate an auto-greet message"),
|
|
492
|
+
] = None,
|
|
493
|
+
host: Annotated[
|
|
494
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
495
|
+
] = None,
|
|
496
|
+
port: Annotated[
|
|
497
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
498
|
+
] = None,
|
|
499
|
+
path: Annotated[
|
|
500
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
501
|
+
] = None,
|
|
502
|
+
room_rules: Annotated[
|
|
503
|
+
List[str],
|
|
504
|
+
typer.Option(
|
|
505
|
+
"--room-rules",
|
|
506
|
+
"-rr",
|
|
507
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
508
|
+
),
|
|
509
|
+
] = [],
|
|
510
|
+
project_id: ProjectIdOption,
|
|
511
|
+
room: Annotated[
|
|
512
|
+
Optional[str],
|
|
513
|
+
typer.Option("--room", help="The name of a room to create the service for"),
|
|
514
|
+
] = None,
|
|
515
|
+
):
|
|
516
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
517
|
+
|
|
518
|
+
CustomVoiceBot = build_voicebot(
|
|
519
|
+
agent_name=agent_name,
|
|
520
|
+
rules=rule,
|
|
521
|
+
rules_file=rules_file,
|
|
522
|
+
toolkits=require_toolkit + toolkit,
|
|
523
|
+
schemas=require_schema + schema,
|
|
524
|
+
auto_greet_message=auto_greet_message,
|
|
525
|
+
auto_greet_prompt=auto_greet_prompt,
|
|
526
|
+
room_rules_paths=room_rules,
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
service = get_service(host=host, port=port)
|
|
530
|
+
|
|
531
|
+
service.agents.append(
|
|
532
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "ChatBot"})
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
if path is None:
|
|
536
|
+
path = "/agent"
|
|
537
|
+
i = 0
|
|
538
|
+
while service.has_path(path):
|
|
539
|
+
i += 1
|
|
540
|
+
path = f"/agent{i}"
|
|
541
|
+
|
|
542
|
+
service.add_path(identity=agent_name, path=path, cls=CustomVoiceBot)
|
|
543
|
+
|
|
544
|
+
spec = service_specs()[0]
|
|
545
|
+
spec.metadata.annotations = {
|
|
546
|
+
"meshagent.service.id": service_name,
|
|
547
|
+
}
|
|
548
|
+
spec.metadata.name = service_name
|
|
549
|
+
spec.metadata.description = service_description
|
|
550
|
+
spec.container.image = (
|
|
551
|
+
"us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz"
|
|
552
|
+
)
|
|
553
|
+
spec.container.command = shlex.join(
|
|
554
|
+
["meshagent", "voicebot", "service", *cleanup_args(sys.argv[2:])]
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
client = await get_client()
|
|
558
|
+
try:
|
|
559
|
+
id = None
|
|
159
560
|
try:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
561
|
+
if id is None:
|
|
562
|
+
if room is None:
|
|
563
|
+
services = await client.list_services(project_id=project_id)
|
|
564
|
+
else:
|
|
565
|
+
services = await client.list_room_services(
|
|
566
|
+
project_id=project_id, room_name=room
|
|
567
|
+
)
|
|
164
568
|
|
|
165
|
-
|
|
569
|
+
for s in services:
|
|
570
|
+
if s.metadata.name == spec.metadata.name:
|
|
571
|
+
id = s.id
|
|
166
572
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
573
|
+
if id is None:
|
|
574
|
+
if room is None:
|
|
575
|
+
id = await client.create_service(
|
|
576
|
+
project_id=project_id, service=spec
|
|
577
|
+
)
|
|
578
|
+
else:
|
|
579
|
+
id = await client.create_room_service(
|
|
580
|
+
project_id=project_id, service=spec, room_name=room
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
else:
|
|
584
|
+
spec.id = id
|
|
585
|
+
if room is None:
|
|
586
|
+
await client.update_service(
|
|
587
|
+
project_id=project_id, service_id=id, service=spec
|
|
588
|
+
)
|
|
589
|
+
else:
|
|
590
|
+
await client.update_room_service(
|
|
591
|
+
project_id=project_id,
|
|
592
|
+
service_id=id,
|
|
593
|
+
service=spec,
|
|
594
|
+
room_name=room,
|
|
595
|
+
)
|
|
177
596
|
|
|
178
|
-
|
|
597
|
+
except ConflictError:
|
|
598
|
+
print(f"[red]Service name already in use: {spec.metadata.name}[/red]")
|
|
599
|
+
raise typer.Exit(code=1)
|
|
600
|
+
else:
|
|
601
|
+
print(f"[green]Deployed service:[/] {id}")
|
|
602
|
+
|
|
603
|
+
finally:
|
|
604
|
+
await client.close()
|
meshagent/cli/webhook.py
CHANGED
|
@@ -7,17 +7,17 @@ from meshagent.cli.common_options import ProjectIdOption
|
|
|
7
7
|
from meshagent.cli import async_typer
|
|
8
8
|
from meshagent.cli.helper import get_client, print_json_table, resolve_project_id
|
|
9
9
|
|
|
10
|
-
app = async_typer.AsyncTyper()
|
|
10
|
+
app = async_typer.AsyncTyper(help="Manage project webhooks")
|
|
11
11
|
|
|
12
12
|
# ---------------------------------------------------------------------------
|
|
13
13
|
# Webhook commands
|
|
14
14
|
# ---------------------------------------------------------------------------
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
@app.async_command("create")
|
|
17
|
+
@app.async_command("create", help="Create a webhook")
|
|
18
18
|
async def webhook_create(
|
|
19
19
|
*,
|
|
20
|
-
project_id: ProjectIdOption
|
|
20
|
+
project_id: ProjectIdOption,
|
|
21
21
|
name: Annotated[str, typer.Option(help="Friendly name for the webhook")],
|
|
22
22
|
url: Annotated[str, typer.Option(help="Target URL that will receive POSTs")],
|
|
23
23
|
event: Annotated[
|
|
@@ -61,10 +61,10 @@ async def webhook_create(
|
|
|
61
61
|
await client.close()
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
@app.async_command("list")
|
|
64
|
+
@app.async_command("list", help="List webhooks")
|
|
65
65
|
async def webhook_list(
|
|
66
66
|
*,
|
|
67
|
-
project_id: ProjectIdOption
|
|
67
|
+
project_id: ProjectIdOption,
|
|
68
68
|
):
|
|
69
69
|
"""List all webhooks for the project."""
|
|
70
70
|
client = await get_client()
|
|
@@ -84,10 +84,10 @@ async def webhook_list(
|
|
|
84
84
|
await client.close()
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
@app.async_command("delete")
|
|
87
|
+
@app.async_command("delete", help="Delete a webhook")
|
|
88
88
|
async def webhook_delete(
|
|
89
89
|
*,
|
|
90
|
-
project_id: ProjectIdOption
|
|
90
|
+
project_id: ProjectIdOption,
|
|
91
91
|
webhook_id: Annotated[str, typer.Argument(help="ID of the webhook to delete")],
|
|
92
92
|
):
|
|
93
93
|
"""Delete a project webhook."""
|