meshagent-cli 0.7.0__py3-none-any.whl → 0.23.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 +23 -13
- meshagent/cli/api_keys.py +4 -4
- meshagent/cli/async_typer.py +52 -4
- meshagent/cli/call.py +27 -36
- meshagent/cli/chatbot.py +1559 -177
- meshagent/cli/cli.py +23 -22
- 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 +101 -12
- meshagent/cli/helpers.py +65 -11
- meshagent/cli/host.py +41 -0
- meshagent/cli/mailbot.py +1104 -79
- meshagent/cli/mailboxes.py +223 -0
- meshagent/cli/meeting_transcriber.py +29 -15
- meshagent/cli/messaging.py +7 -10
- meshagent/cli/multi.py +357 -0
- meshagent/cli/oauth2.py +192 -40
- meshagent/cli/participant_token.py +5 -3
- meshagent/cli/port.py +70 -0
- meshagent/cli/queue.py +2 -2
- meshagent/cli/room.py +24 -212
- meshagent/cli/rooms.py +214 -0
- meshagent/cli/services.py +269 -37
- meshagent/cli/sessions.py +5 -5
- meshagent/cli/storage.py +5 -5
- meshagent/cli/sync.py +434 -0
- meshagent/cli/task_runner.py +1317 -0
- meshagent/cli/version.py +1 -1
- meshagent/cli/voicebot.py +544 -98
- meshagent/cli/webhook.py +7 -7
- meshagent/cli/worker.py +1403 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/METADATA +15 -13
- meshagent_cli-0.23.0.dist-info/RECORD +45 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/WHEEL +1 -1
- meshagent_cli-0.7.0.dist-info/RECORD +0 -36
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/entry_points.txt +0 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/top_level.txt +0 -0
meshagent/cli/mailbot.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import typer
|
|
2
|
-
from meshagent.
|
|
2
|
+
from meshagent.cli import async_typer
|
|
3
3
|
from rich import print
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from meshagent.api import ParticipantToken
|
|
4
7
|
from typing import Annotated, Optional
|
|
5
8
|
from meshagent.cli.common_options import (
|
|
6
9
|
ProjectIdOption,
|
|
@@ -9,24 +12,53 @@ from meshagent.cli.common_options import (
|
|
|
9
12
|
from meshagent.tools import Toolkit
|
|
10
13
|
from meshagent.api import RoomClient, WebSocketClientProtocol, ApiScope
|
|
11
14
|
from meshagent.api.helpers import meshagent_base_url, websocket_room_url
|
|
12
|
-
from meshagent.cli import async_typer
|
|
13
15
|
from meshagent.cli.helper import (
|
|
14
16
|
get_client,
|
|
15
17
|
resolve_project_id,
|
|
16
18
|
resolve_room,
|
|
17
19
|
resolve_key,
|
|
20
|
+
cleanup_args,
|
|
18
21
|
)
|
|
19
22
|
from meshagent.openai import OpenAIResponsesAdapter
|
|
20
|
-
from meshagent.
|
|
21
|
-
from meshagent.api.services import ServiceHost
|
|
23
|
+
from meshagent.anthropic import AnthropicOpenAIResponsesStreamAdapter
|
|
22
24
|
|
|
25
|
+
from meshagent.agents.config import RulesConfig
|
|
23
26
|
|
|
24
27
|
from typing import List
|
|
25
28
|
from pathlib import Path
|
|
26
29
|
|
|
27
|
-
from meshagent.api import RequiredToolkit, RequiredSchema
|
|
28
|
-
|
|
30
|
+
from meshagent.api import RequiredToolkit, RequiredSchema, RoomException
|
|
31
|
+
|
|
32
|
+
import logging
|
|
33
|
+
|
|
34
|
+
from meshagent.tools.database import DatabaseToolkitBuilder, DatabaseToolkitConfig
|
|
35
|
+
|
|
36
|
+
from meshagent.tools.storage import StorageToolkit
|
|
37
|
+
from meshagent.tools.datetime import DatetimeToolkit
|
|
38
|
+
from meshagent.tools.uuid import UUIDToolkit
|
|
39
|
+
|
|
40
|
+
from meshagent.openai.tools.responses_adapter import (
|
|
41
|
+
WebSearchTool,
|
|
42
|
+
ShellConfig,
|
|
43
|
+
ApplyPatchConfig,
|
|
44
|
+
ApplyPatchTool,
|
|
45
|
+
ShellTool,
|
|
46
|
+
LocalShellTool,
|
|
47
|
+
ImageGenerationTool,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
from meshagent.cli.host import get_service, run_services, get_deferred, service_specs
|
|
51
|
+
from meshagent.api.specs.service import AgentSpec, ANNOTATION_AGENT_TYPE
|
|
29
52
|
|
|
53
|
+
import yaml
|
|
54
|
+
|
|
55
|
+
import shlex
|
|
56
|
+
import sys
|
|
57
|
+
|
|
58
|
+
from meshagent.api.client import ConflictError
|
|
59
|
+
from meshagent.agents.adapter import MessageStreamLLMAdapter
|
|
60
|
+
|
|
61
|
+
logger = logging.getLogger("mailbot")
|
|
30
62
|
|
|
31
63
|
app = async_typer.AsyncTyper(help="Join a mailbot to a room")
|
|
32
64
|
|
|
@@ -34,7 +66,6 @@ app = async_typer.AsyncTyper(help="Join a mailbot to a room")
|
|
|
34
66
|
def build_mailbot(
|
|
35
67
|
*,
|
|
36
68
|
model: str,
|
|
37
|
-
agent_name: str,
|
|
38
69
|
rule: List[str],
|
|
39
70
|
toolkit: List[str],
|
|
40
71
|
schema: List[str],
|
|
@@ -45,10 +76,36 @@ def build_mailbot(
|
|
|
45
76
|
web_search: Annotated[
|
|
46
77
|
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
47
78
|
] = False,
|
|
48
|
-
|
|
79
|
+
toolkit_name: Optional[str] = None,
|
|
80
|
+
queue: Optional[str] = None,
|
|
49
81
|
email_address: str,
|
|
82
|
+
room_rules_paths: list[str],
|
|
83
|
+
whitelist=list[str],
|
|
84
|
+
require_shell: Optional[bool] = None,
|
|
85
|
+
require_apply_patch: Optional[bool] = None,
|
|
86
|
+
require_storage: Optional[str] = None,
|
|
87
|
+
require_read_only_storage: Optional[str] = None,
|
|
88
|
+
require_time: bool = True,
|
|
89
|
+
require_uuid: bool = False,
|
|
90
|
+
require_table_read: bool,
|
|
91
|
+
require_table_write: bool,
|
|
92
|
+
require_computer_use: bool,
|
|
93
|
+
reply_all: bool,
|
|
94
|
+
database_namespace: Optional[list[str]] = None,
|
|
95
|
+
enable_attachments: bool,
|
|
96
|
+
working_directory: Optional[str] = None,
|
|
97
|
+
skill_dirs: Optional[list[str]] = None,
|
|
98
|
+
shell_image: Optional[str] = None,
|
|
99
|
+
llm_participant: Optional[str] = None,
|
|
100
|
+
delegate_shell_token: Optional[bool] = None,
|
|
101
|
+
log_llm_requests: Optional[bool] = None,
|
|
50
102
|
):
|
|
51
|
-
from meshagent.agents.mail import
|
|
103
|
+
from meshagent.agents.mail import MailBot
|
|
104
|
+
|
|
105
|
+
if (require_storage or require_read_only_storage) and len(whitelist) == 0:
|
|
106
|
+
logger.warning(
|
|
107
|
+
"you have enabled storage tools without a whilelist, anyone who can send to this mailbox will be able to ask it about files"
|
|
108
|
+
)
|
|
52
109
|
|
|
53
110
|
requirements = []
|
|
54
111
|
|
|
@@ -67,29 +124,117 @@ def build_mailbot(
|
|
|
67
124
|
except FileNotFoundError:
|
|
68
125
|
print(f"[yellow]rules file not found at {rules_file}[/yellow]")
|
|
69
126
|
|
|
70
|
-
BaseClass =
|
|
71
|
-
if
|
|
72
|
-
|
|
127
|
+
BaseClass = MailBot
|
|
128
|
+
if llm_participant:
|
|
129
|
+
llm_adapter = MessageStreamLLMAdapter(
|
|
130
|
+
participant_name=llm_participant,
|
|
131
|
+
)
|
|
73
132
|
else:
|
|
74
|
-
|
|
133
|
+
if computer_use or require_computer_use:
|
|
134
|
+
llm_adapter = OpenAIResponsesAdapter(
|
|
135
|
+
model=model,
|
|
136
|
+
response_options={
|
|
137
|
+
"reasoning": {"summary": "concise"},
|
|
138
|
+
"truncation": "auto",
|
|
139
|
+
},
|
|
140
|
+
log_requests=log_llm_requests,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
else:
|
|
144
|
+
if model.startswith("claude-"):
|
|
145
|
+
llm_adapter = AnthropicOpenAIResponsesStreamAdapter(
|
|
146
|
+
model=model,
|
|
147
|
+
log_requests=log_llm_requests,
|
|
148
|
+
)
|
|
149
|
+
else:
|
|
150
|
+
llm_adapter = OpenAIResponsesAdapter(
|
|
151
|
+
model=model,
|
|
152
|
+
log_requests=log_llm_requests,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
parsed_whitelist = []
|
|
156
|
+
if len(whitelist) > 0:
|
|
157
|
+
for w in whitelist:
|
|
158
|
+
for s in w.split(","):
|
|
159
|
+
s = s.strip()
|
|
160
|
+
if len(s) > 0:
|
|
161
|
+
parsed_whitelist.append(s)
|
|
75
162
|
|
|
76
163
|
class CustomMailbot(BaseClass):
|
|
77
164
|
def __init__(self):
|
|
78
165
|
super().__init__(
|
|
79
166
|
llm_adapter=llm_adapter,
|
|
80
|
-
name=agent_name,
|
|
81
167
|
requires=requirements,
|
|
82
168
|
toolkits=toolkits,
|
|
83
169
|
queue=queue,
|
|
84
170
|
email_address=email_address,
|
|
171
|
+
toolkit_name=toolkit_name,
|
|
85
172
|
rules=rule if len(rule) > 0 else None,
|
|
173
|
+
whitelist=parsed_whitelist if len(parsed_whitelist) > 0 else None,
|
|
174
|
+
reply_all=reply_all,
|
|
175
|
+
enable_attachments=enable_attachments,
|
|
176
|
+
skill_dirs=skill_dirs,
|
|
86
177
|
)
|
|
87
178
|
|
|
179
|
+
async def init_chat_context(self):
|
|
180
|
+
from meshagent.cli.helper import init_context_from_spec
|
|
181
|
+
|
|
182
|
+
context = await super().init_chat_context()
|
|
183
|
+
await init_context_from_spec(context)
|
|
184
|
+
|
|
185
|
+
return context
|
|
186
|
+
|
|
88
187
|
async def start(self, *, room: RoomClient):
|
|
89
188
|
print(
|
|
90
189
|
"[bold green]Configure and send an email interact with your mailbot[/bold green]"
|
|
91
190
|
)
|
|
92
|
-
|
|
191
|
+
await super().start(room=room)
|
|
192
|
+
if room_rules_paths is not None:
|
|
193
|
+
for p in room_rules_paths:
|
|
194
|
+
await self._load_room_rules(path=p)
|
|
195
|
+
|
|
196
|
+
async def get_rules(self):
|
|
197
|
+
rules = [*await super().get_rules()]
|
|
198
|
+
if room_rules_paths is not None:
|
|
199
|
+
for p in room_rules_paths:
|
|
200
|
+
rules.extend(await self._load_room_rules(path=p))
|
|
201
|
+
|
|
202
|
+
return rules
|
|
203
|
+
|
|
204
|
+
async def _load_room_rules(
|
|
205
|
+
self,
|
|
206
|
+
*,
|
|
207
|
+
path: str,
|
|
208
|
+
):
|
|
209
|
+
rules = []
|
|
210
|
+
try:
|
|
211
|
+
room_rules = await self.room.storage.download(path=path)
|
|
212
|
+
|
|
213
|
+
rules_txt = room_rules.data.decode()
|
|
214
|
+
|
|
215
|
+
rules_config = RulesConfig.parse(rules_txt)
|
|
216
|
+
|
|
217
|
+
if rules_config.rules is not None:
|
|
218
|
+
rules.extend(rules_config.rules)
|
|
219
|
+
|
|
220
|
+
except RoomException:
|
|
221
|
+
try:
|
|
222
|
+
logger.info("attempting to initialize rules file")
|
|
223
|
+
handle = await self.room.storage.open(path=path, overwrite=False)
|
|
224
|
+
await self.room.storage.write(
|
|
225
|
+
handle=handle,
|
|
226
|
+
data="# Add rules to this file to customize your agent's behavior, lines starting with # will be ignored.\n\n".encode(),
|
|
227
|
+
)
|
|
228
|
+
await self.room.storage.close(handle=handle)
|
|
229
|
+
|
|
230
|
+
except RoomException:
|
|
231
|
+
pass
|
|
232
|
+
logger.info(
|
|
233
|
+
f"unable to load rules from {path}, continuing with default rules"
|
|
234
|
+
)
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
return rules
|
|
93
238
|
|
|
94
239
|
async def get_thread_toolkits(self, *, thread_context):
|
|
95
240
|
toolkits = await super().get_thread_toolkits(thread_context=thread_context)
|
|
@@ -101,6 +246,27 @@ def build_mailbot(
|
|
|
101
246
|
LocalShellTool(thread_context=thread_context)
|
|
102
247
|
)
|
|
103
248
|
|
|
249
|
+
env = {}
|
|
250
|
+
if delegate_shell_token:
|
|
251
|
+
env["MESHAGENT_TOKEN"] = self.room.protocol.token
|
|
252
|
+
|
|
253
|
+
if require_shell:
|
|
254
|
+
thread_toolkit.tools.append(
|
|
255
|
+
ShellTool(
|
|
256
|
+
working_directory=working_directory,
|
|
257
|
+
config=ShellConfig(name="shell"),
|
|
258
|
+
image=shell_image or "python:3.13",
|
|
259
|
+
env=env,
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
if require_apply_patch:
|
|
264
|
+
thread_toolkit.tools.append(
|
|
265
|
+
ApplyPatchTool(
|
|
266
|
+
config=ApplyPatchConfig(name="apply_patch"),
|
|
267
|
+
)
|
|
268
|
+
)
|
|
269
|
+
|
|
104
270
|
if image_generation is not None:
|
|
105
271
|
print("adding openai image gen to thread", flush=True)
|
|
106
272
|
thread_toolkit.tools.append(
|
|
@@ -114,6 +280,55 @@ def build_mailbot(
|
|
|
114
280
|
if web_search:
|
|
115
281
|
thread_toolkit.tools.append(WebSearchTool())
|
|
116
282
|
|
|
283
|
+
if require_storage:
|
|
284
|
+
thread_toolkit.tools.extend(StorageToolkit().tools)
|
|
285
|
+
|
|
286
|
+
if require_read_only_storage:
|
|
287
|
+
thread_toolkit.tools.extend(StorageToolkit(read_only=True).tools)
|
|
288
|
+
|
|
289
|
+
if len(require_table_read) > 0:
|
|
290
|
+
thread_toolkit.tools.extend(
|
|
291
|
+
(
|
|
292
|
+
await DatabaseToolkitBuilder().make(
|
|
293
|
+
room=self.room,
|
|
294
|
+
model=model,
|
|
295
|
+
config=DatabaseToolkitConfig(
|
|
296
|
+
tables=require_table_read,
|
|
297
|
+
read_only=True,
|
|
298
|
+
namespace=database_namespace,
|
|
299
|
+
),
|
|
300
|
+
)
|
|
301
|
+
).tools
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
if len(require_table_write) > 0:
|
|
305
|
+
thread_toolkit.tools.extend(
|
|
306
|
+
(
|
|
307
|
+
await DatabaseToolkitBuilder().make(
|
|
308
|
+
room=self.room,
|
|
309
|
+
model=model,
|
|
310
|
+
config=DatabaseToolkitConfig(
|
|
311
|
+
tables=require_table_write,
|
|
312
|
+
read_only=False,
|
|
313
|
+
namespace=database_namespace,
|
|
314
|
+
),
|
|
315
|
+
)
|
|
316
|
+
).tools
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
if require_time:
|
|
320
|
+
thread_toolkit.tools.extend(DatetimeToolkit().tools)
|
|
321
|
+
|
|
322
|
+
if require_uuid:
|
|
323
|
+
thread_toolkit.tools.extend(UUIDToolkit().tools)
|
|
324
|
+
|
|
325
|
+
if require_computer_use:
|
|
326
|
+
from meshagent.computers.agent import ComputerToolkit
|
|
327
|
+
|
|
328
|
+
computer_toolkit = ComputerToolkit(room=self.room, render_screen=None)
|
|
329
|
+
|
|
330
|
+
toolkits.append(computer_toolkit)
|
|
331
|
+
|
|
117
332
|
toolkits.append(thread_toolkit)
|
|
118
333
|
return toolkits
|
|
119
334
|
|
|
@@ -121,14 +336,28 @@ def build_mailbot(
|
|
|
121
336
|
|
|
122
337
|
|
|
123
338
|
@app.async_command("join")
|
|
124
|
-
async def
|
|
339
|
+
async def join(
|
|
125
340
|
*,
|
|
126
|
-
project_id: ProjectIdOption
|
|
341
|
+
project_id: ProjectIdOption,
|
|
127
342
|
room: RoomOption,
|
|
128
343
|
role: str = "agent",
|
|
129
|
-
agent_name: Annotated[
|
|
344
|
+
agent_name: Annotated[
|
|
345
|
+
Optional[str], typer.Option(..., help="Name of the agent to call")
|
|
346
|
+
] = None,
|
|
130
347
|
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
131
348
|
rules_file: Optional[str] = None,
|
|
349
|
+
require_toolkit: Annotated[
|
|
350
|
+
List[str],
|
|
351
|
+
typer.Option(
|
|
352
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
353
|
+
),
|
|
354
|
+
] = [],
|
|
355
|
+
require_schema: Annotated[
|
|
356
|
+
List[str],
|
|
357
|
+
typer.Option(
|
|
358
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
359
|
+
),
|
|
360
|
+
] = [],
|
|
132
361
|
toolkit: Annotated[
|
|
133
362
|
List[str],
|
|
134
363
|
typer.Option("--toolkit", "-t", help="the name or url of a required toolkit"),
|
|
@@ -139,21 +368,121 @@ async def make_call(
|
|
|
139
368
|
] = [],
|
|
140
369
|
model: Annotated[
|
|
141
370
|
str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
|
|
142
|
-
] = "gpt-5",
|
|
143
|
-
|
|
371
|
+
] = "gpt-5.2",
|
|
372
|
+
require_shell: Annotated[
|
|
373
|
+
Optional[bool],
|
|
374
|
+
typer.Option(..., help="Enable function shell tool calling"),
|
|
375
|
+
] = False,
|
|
376
|
+
require_local_shell: Annotated[
|
|
144
377
|
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
145
378
|
] = False,
|
|
146
|
-
|
|
379
|
+
require_web_search: Annotated[
|
|
147
380
|
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
148
381
|
] = False,
|
|
382
|
+
require_apply_patch: Annotated[
|
|
383
|
+
Optional[bool],
|
|
384
|
+
typer.Option(..., help="Enable apply patch tool calling"),
|
|
385
|
+
] = False,
|
|
149
386
|
key: Annotated[
|
|
150
387
|
str,
|
|
151
388
|
typer.Option("--key", help="an api key to sign the token with"),
|
|
152
389
|
] = None,
|
|
153
|
-
queue: Annotated[
|
|
390
|
+
queue: Annotated[
|
|
391
|
+
Optional[str], typer.Option(..., help="the name of the mail queue")
|
|
392
|
+
] = None,
|
|
154
393
|
email_address: Annotated[
|
|
155
394
|
str, typer.Option(..., help="the email address of the agent")
|
|
156
395
|
],
|
|
396
|
+
toolkit_name: Annotated[
|
|
397
|
+
Optional[str],
|
|
398
|
+
typer.Option(..., help="the name of a toolkit to expose mail operations"),
|
|
399
|
+
] = None,
|
|
400
|
+
room_rules: Annotated[
|
|
401
|
+
List[str],
|
|
402
|
+
typer.Option(
|
|
403
|
+
"--room-rules",
|
|
404
|
+
"-rr",
|
|
405
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
406
|
+
),
|
|
407
|
+
] = [],
|
|
408
|
+
whitelist: Annotated[
|
|
409
|
+
List[str],
|
|
410
|
+
typer.Option(
|
|
411
|
+
"--whitelist",
|
|
412
|
+
help="an email to whitelist",
|
|
413
|
+
),
|
|
414
|
+
] = [],
|
|
415
|
+
require_storage: Annotated[
|
|
416
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit")
|
|
417
|
+
] = False,
|
|
418
|
+
require_read_only_storage: Annotated[
|
|
419
|
+
Optional[bool],
|
|
420
|
+
typer.Option(..., help="Enable read only storage toolkit"),
|
|
421
|
+
] = False,
|
|
422
|
+
require_time: Annotated[
|
|
423
|
+
bool,
|
|
424
|
+
typer.Option(
|
|
425
|
+
...,
|
|
426
|
+
help="Enable time/datetime tools",
|
|
427
|
+
),
|
|
428
|
+
] = True,
|
|
429
|
+
require_uuid: Annotated[
|
|
430
|
+
bool,
|
|
431
|
+
typer.Option(
|
|
432
|
+
...,
|
|
433
|
+
help="Enable UUID generation tools",
|
|
434
|
+
),
|
|
435
|
+
] = False,
|
|
436
|
+
database_namespace: Annotated[
|
|
437
|
+
Optional[str],
|
|
438
|
+
typer.Option(..., help="Use a specific database namespace"),
|
|
439
|
+
] = None,
|
|
440
|
+
require_table_read: Annotated[
|
|
441
|
+
list[str],
|
|
442
|
+
typer.Option(..., help="Enable table read tools for a specific table"),
|
|
443
|
+
] = [],
|
|
444
|
+
require_table_write: Annotated[
|
|
445
|
+
list[str],
|
|
446
|
+
typer.Option(..., help="Enable table write tools for a specific table"),
|
|
447
|
+
] = [],
|
|
448
|
+
require_computer_use: Annotated[
|
|
449
|
+
Optional[bool],
|
|
450
|
+
typer.Option(
|
|
451
|
+
...,
|
|
452
|
+
help="Enable computer use (requires computer-use-preview model)",
|
|
453
|
+
hidden=True,
|
|
454
|
+
),
|
|
455
|
+
] = False,
|
|
456
|
+
reply_all: Annotated[
|
|
457
|
+
bool, typer.Option(help="Reply-all when responding to emails")
|
|
458
|
+
] = False,
|
|
459
|
+
enable_attachments: Annotated[
|
|
460
|
+
bool, typer.Option(help="Allow downloading and processing email attachments")
|
|
461
|
+
] = False,
|
|
462
|
+
working_directory: Annotated[
|
|
463
|
+
Optional[str],
|
|
464
|
+
typer.Option(..., help="The default working directory for shell commands"),
|
|
465
|
+
] = None,
|
|
466
|
+
skill_dir: Annotated[
|
|
467
|
+
list[str],
|
|
468
|
+
typer.Option(..., help="an agent skills directory"),
|
|
469
|
+
] = [],
|
|
470
|
+
llm_participant: Annotated[
|
|
471
|
+
Optional[str],
|
|
472
|
+
typer.Option(..., help="Delegate LLM interactions to a remote participant"),
|
|
473
|
+
] = None,
|
|
474
|
+
shell_image: Annotated[
|
|
475
|
+
Optional[str],
|
|
476
|
+
typer.Option(..., help="an image tag to use to run shell commands in"),
|
|
477
|
+
] = None,
|
|
478
|
+
delegate_shell_token: Annotated[
|
|
479
|
+
Optional[bool],
|
|
480
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
481
|
+
] = False,
|
|
482
|
+
log_llm_requests: Annotated[
|
|
483
|
+
Optional[bool],
|
|
484
|
+
typer.Option(..., help="log all requests to the llm"),
|
|
485
|
+
] = False,
|
|
157
486
|
):
|
|
158
487
|
key = await resolve_key(project_id=project_id, key=key)
|
|
159
488
|
|
|
@@ -163,57 +492,84 @@ async def make_call(
|
|
|
163
492
|
|
|
164
493
|
room = resolve_room(room)
|
|
165
494
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
495
|
+
jwt = os.getenv("MESHAGENT_TOKEN")
|
|
496
|
+
if jwt is None:
|
|
497
|
+
if agent_name is None:
|
|
498
|
+
print(
|
|
499
|
+
"[bold red]--agent-name must be specified when the MESHAGENT_TOKEN environment variable is not set[/bold red]"
|
|
500
|
+
)
|
|
501
|
+
raise typer.Exit(1)
|
|
171
502
|
|
|
172
|
-
|
|
173
|
-
|
|
503
|
+
token = ParticipantToken(
|
|
504
|
+
name=agent_name,
|
|
505
|
+
)
|
|
174
506
|
|
|
175
|
-
|
|
507
|
+
token.add_api_grant(ApiScope.agent_default(tunnels=require_computer_use))
|
|
176
508
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
protocol=WebSocketClientProtocol(
|
|
180
|
-
url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
|
|
181
|
-
token=jwt,
|
|
182
|
-
)
|
|
183
|
-
) as client:
|
|
184
|
-
requirements = []
|
|
509
|
+
token.add_role_grant(role=role)
|
|
510
|
+
token.add_room_grant(room)
|
|
185
511
|
|
|
186
|
-
|
|
187
|
-
requirements.append(RequiredToolkit(name=t))
|
|
512
|
+
jwt = token.to_jwt(api_key=key)
|
|
188
513
|
|
|
189
|
-
|
|
190
|
-
|
|
514
|
+
print("[bold green]Connecting to room...[/bold green]", flush=True)
|
|
515
|
+
CustomMailbot = build_mailbot(
|
|
516
|
+
computer_use=None,
|
|
517
|
+
model=model,
|
|
518
|
+
local_shell=require_local_shell,
|
|
519
|
+
rule=rule,
|
|
520
|
+
schema=require_schema + schema,
|
|
521
|
+
toolkit=require_toolkit + toolkit,
|
|
522
|
+
image_generation=None,
|
|
523
|
+
web_search=require_web_search,
|
|
524
|
+
rules_file=rules_file,
|
|
525
|
+
queue=queue,
|
|
526
|
+
email_address=email_address,
|
|
527
|
+
toolkit_name=toolkit_name,
|
|
528
|
+
room_rules_paths=room_rules,
|
|
529
|
+
whitelist=whitelist,
|
|
530
|
+
require_shell=require_shell,
|
|
531
|
+
require_apply_patch=require_apply_patch,
|
|
532
|
+
require_storage=require_storage,
|
|
533
|
+
require_read_only_storage=require_read_only_storage,
|
|
534
|
+
require_time=require_time,
|
|
535
|
+
require_uuid=require_uuid,
|
|
536
|
+
require_table_read=require_table_read,
|
|
537
|
+
require_table_write=require_table_write,
|
|
538
|
+
require_computer_use=require_computer_use,
|
|
539
|
+
reply_all=reply_all,
|
|
540
|
+
database_namespace=database_namespace,
|
|
541
|
+
enable_attachments=enable_attachments,
|
|
542
|
+
working_directory=working_directory,
|
|
543
|
+
skill_dirs=skill_dir,
|
|
544
|
+
shell_image=shell_image,
|
|
545
|
+
llm_participant=llm_participant,
|
|
546
|
+
delegate_shell_token=delegate_shell_token,
|
|
547
|
+
log_llm_requests=log_llm_requests,
|
|
548
|
+
)
|
|
191
549
|
|
|
192
|
-
|
|
193
|
-
computer_use=None,
|
|
194
|
-
model=model,
|
|
195
|
-
local_shell=local_shell,
|
|
196
|
-
agent_name=agent_name,
|
|
197
|
-
rule=rule,
|
|
198
|
-
toolkit=toolkit,
|
|
199
|
-
schema=schema,
|
|
200
|
-
image_generation=None,
|
|
201
|
-
web_search=web_search,
|
|
202
|
-
rules_file=rules_file,
|
|
203
|
-
queue=queue,
|
|
204
|
-
email_address=email_address,
|
|
205
|
-
)
|
|
550
|
+
bot = CustomMailbot()
|
|
206
551
|
|
|
207
|
-
|
|
552
|
+
if get_deferred():
|
|
553
|
+
from meshagent.cli.host import agents
|
|
208
554
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
555
|
+
agents.append((bot, jwt))
|
|
556
|
+
else:
|
|
557
|
+
async with RoomClient(
|
|
558
|
+
protocol=WebSocketClientProtocol(
|
|
559
|
+
url=websocket_room_url(
|
|
560
|
+
room_name=room, base_url=meshagent_base_url()
|
|
561
|
+
),
|
|
562
|
+
token=jwt,
|
|
213
563
|
)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
564
|
+
) as client:
|
|
565
|
+
await bot.start(room=client)
|
|
566
|
+
try:
|
|
567
|
+
print(
|
|
568
|
+
flush=True,
|
|
569
|
+
)
|
|
570
|
+
await client.protocol.wait_for_close()
|
|
571
|
+
except KeyboardInterrupt:
|
|
572
|
+
await bot.stop()
|
|
217
573
|
|
|
218
574
|
finally:
|
|
219
575
|
await account_client.close()
|
|
@@ -225,46 +581,715 @@ async def service(
|
|
|
225
581
|
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
226
582
|
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
227
583
|
rules_file: Optional[str] = None,
|
|
584
|
+
require_toolkit: Annotated[
|
|
585
|
+
List[str],
|
|
586
|
+
typer.Option(
|
|
587
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
588
|
+
),
|
|
589
|
+
] = [],
|
|
590
|
+
require_schema: Annotated[
|
|
591
|
+
List[str],
|
|
592
|
+
typer.Option(
|
|
593
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
594
|
+
),
|
|
595
|
+
] = [],
|
|
228
596
|
toolkit: Annotated[
|
|
229
597
|
List[str],
|
|
230
|
-
typer.Option(
|
|
598
|
+
typer.Option(
|
|
599
|
+
"--toolkit", "-t", help="the name or url of a required toolkit", hidden=True
|
|
600
|
+
),
|
|
231
601
|
] = [],
|
|
232
602
|
schema: Annotated[
|
|
233
603
|
List[str],
|
|
234
|
-
typer.Option(
|
|
604
|
+
typer.Option(
|
|
605
|
+
"--schema", "-s", help="the name or url of a required schema", hidden=True
|
|
606
|
+
),
|
|
607
|
+
] = [],
|
|
608
|
+
model: Annotated[
|
|
609
|
+
str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
|
|
610
|
+
] = "gpt-5.2",
|
|
611
|
+
require_shell: Annotated[
|
|
612
|
+
Optional[bool],
|
|
613
|
+
typer.Option(..., help="Enable function shell tool calling"),
|
|
614
|
+
] = False,
|
|
615
|
+
require_local_shell: Annotated[
|
|
616
|
+
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
617
|
+
] = False,
|
|
618
|
+
require_web_search: Annotated[
|
|
619
|
+
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
620
|
+
] = False,
|
|
621
|
+
require_apply_patch: Annotated[
|
|
622
|
+
Optional[bool],
|
|
623
|
+
typer.Option(..., help="Enable apply patch tool calling"),
|
|
624
|
+
] = False,
|
|
625
|
+
host: Annotated[
|
|
626
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
627
|
+
] = None,
|
|
628
|
+
port: Annotated[
|
|
629
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
630
|
+
] = None,
|
|
631
|
+
path: Annotated[
|
|
632
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
633
|
+
] = None,
|
|
634
|
+
queue: Annotated[
|
|
635
|
+
Optional[str], typer.Option(..., help="the name of the mail queue")
|
|
636
|
+
] = None,
|
|
637
|
+
email_address: Annotated[
|
|
638
|
+
str, typer.Option(..., help="the email address of the agent")
|
|
639
|
+
],
|
|
640
|
+
toolkit_name: Annotated[
|
|
641
|
+
Optional[str],
|
|
642
|
+
typer.Option(..., help="the name of a toolkit to expose mail operations"),
|
|
643
|
+
] = None,
|
|
644
|
+
room_rules: Annotated[
|
|
645
|
+
List[str],
|
|
646
|
+
typer.Option(
|
|
647
|
+
"--room-rules",
|
|
648
|
+
"-rr",
|
|
649
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
650
|
+
),
|
|
651
|
+
] = [],
|
|
652
|
+
whitelist: Annotated[
|
|
653
|
+
List[str],
|
|
654
|
+
typer.Option(
|
|
655
|
+
"--whitelist",
|
|
656
|
+
help="an email to whitelist",
|
|
657
|
+
),
|
|
658
|
+
] = [],
|
|
659
|
+
require_storage: Annotated[
|
|
660
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit")
|
|
661
|
+
] = False,
|
|
662
|
+
require_read_only_storage: Annotated[
|
|
663
|
+
Optional[bool],
|
|
664
|
+
typer.Option(..., help="Enable read only storage toolkit"),
|
|
665
|
+
] = False,
|
|
666
|
+
require_time: Annotated[
|
|
667
|
+
bool,
|
|
668
|
+
typer.Option(
|
|
669
|
+
...,
|
|
670
|
+
help="Enable time/datetime tools",
|
|
671
|
+
),
|
|
672
|
+
] = True,
|
|
673
|
+
require_uuid: Annotated[
|
|
674
|
+
bool,
|
|
675
|
+
typer.Option(
|
|
676
|
+
...,
|
|
677
|
+
help="Enable UUID generation tools",
|
|
678
|
+
),
|
|
679
|
+
] = False,
|
|
680
|
+
database_namespace: Annotated[
|
|
681
|
+
Optional[str],
|
|
682
|
+
typer.Option(..., help="Use a specific database namespace"),
|
|
683
|
+
] = None,
|
|
684
|
+
require_table_read: Annotated[
|
|
685
|
+
list[str],
|
|
686
|
+
typer.Option(..., help="Enable table read tools for a specific table"),
|
|
687
|
+
] = [],
|
|
688
|
+
require_table_write: Annotated[
|
|
689
|
+
list[str],
|
|
690
|
+
typer.Option(..., help="Enable table write tools for a specific table"),
|
|
691
|
+
] = [],
|
|
692
|
+
require_computer_use: Annotated[
|
|
693
|
+
Optional[bool],
|
|
694
|
+
typer.Option(
|
|
695
|
+
...,
|
|
696
|
+
help="Enable computer use (requires computer-use-preview model)",
|
|
697
|
+
hidden=True,
|
|
698
|
+
),
|
|
699
|
+
] = False,
|
|
700
|
+
reply_all: Annotated[
|
|
701
|
+
bool, typer.Option(help="Reply-all when responding to emails")
|
|
702
|
+
] = False,
|
|
703
|
+
enable_attachments: Annotated[
|
|
704
|
+
bool, typer.Option(help="Allow downloading and processing email attachments")
|
|
705
|
+
] = False,
|
|
706
|
+
working_directory: Annotated[
|
|
707
|
+
Optional[str],
|
|
708
|
+
typer.Option(..., help="The default working directory for shell commands"),
|
|
709
|
+
] = None,
|
|
710
|
+
skill_dir: Annotated[
|
|
711
|
+
list[str],
|
|
712
|
+
typer.Option(..., help="an agent skills directory"),
|
|
713
|
+
] = [],
|
|
714
|
+
llm_participant: Annotated[
|
|
715
|
+
Optional[str],
|
|
716
|
+
typer.Option(..., help="Delegate LLM interactions to a remote participant"),
|
|
717
|
+
] = None,
|
|
718
|
+
shell_image: Annotated[
|
|
719
|
+
Optional[str],
|
|
720
|
+
typer.Option(..., help="an image tag to use to run shell commands in"),
|
|
721
|
+
] = None,
|
|
722
|
+
delegate_shell_token: Annotated[
|
|
723
|
+
Optional[bool],
|
|
724
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
725
|
+
] = False,
|
|
726
|
+
log_llm_requests: Annotated[
|
|
727
|
+
Optional[bool],
|
|
728
|
+
typer.Option(..., help="log all requests to the llm"),
|
|
729
|
+
] = False,
|
|
730
|
+
):
|
|
731
|
+
service = get_service(host=host, port=port)
|
|
732
|
+
if path is None:
|
|
733
|
+
path = "/agent"
|
|
734
|
+
i = 0
|
|
735
|
+
while service.has_path(path):
|
|
736
|
+
i += 1
|
|
737
|
+
path = f"/agent{i}"
|
|
738
|
+
|
|
739
|
+
service.agents.append(
|
|
740
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "MailBot"})
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
service.add_path(
|
|
744
|
+
identity=agent_name,
|
|
745
|
+
path=path,
|
|
746
|
+
cls=build_mailbot(
|
|
747
|
+
queue=queue,
|
|
748
|
+
computer_use=None,
|
|
749
|
+
model=model,
|
|
750
|
+
local_shell=require_local_shell,
|
|
751
|
+
web_search=require_web_search,
|
|
752
|
+
rule=rule,
|
|
753
|
+
schema=require_schema + schema,
|
|
754
|
+
toolkit=require_toolkit + toolkit,
|
|
755
|
+
image_generation=None,
|
|
756
|
+
rules_file=rules_file,
|
|
757
|
+
email_address=email_address,
|
|
758
|
+
toolkit_name=toolkit_name,
|
|
759
|
+
room_rules_paths=room_rules,
|
|
760
|
+
whitelist=whitelist,
|
|
761
|
+
require_shell=require_shell,
|
|
762
|
+
require_apply_patch=require_apply_patch,
|
|
763
|
+
require_storage=require_storage,
|
|
764
|
+
require_read_only_storage=require_read_only_storage,
|
|
765
|
+
require_time=require_time,
|
|
766
|
+
require_uuid=require_uuid,
|
|
767
|
+
require_table_read=require_table_read,
|
|
768
|
+
require_table_write=require_table_write,
|
|
769
|
+
require_computer_use=require_computer_use,
|
|
770
|
+
reply_all=reply_all,
|
|
771
|
+
database_namespace=database_namespace,
|
|
772
|
+
enable_attachments=enable_attachments,
|
|
773
|
+
working_directory=working_directory,
|
|
774
|
+
skill_dirs=skill_dir,
|
|
775
|
+
shell_image=shell_image,
|
|
776
|
+
llm_participant=llm_participant,
|
|
777
|
+
delegate_shell_token=delegate_shell_token,
|
|
778
|
+
log_llm_requests=log_llm_requests,
|
|
779
|
+
),
|
|
780
|
+
)
|
|
781
|
+
|
|
782
|
+
if not get_deferred():
|
|
783
|
+
await run_services()
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
@app.async_command("spec")
|
|
787
|
+
async def spec(
|
|
788
|
+
*,
|
|
789
|
+
service_name: Annotated[str, typer.Option("--service-name", help="service name")],
|
|
790
|
+
service_description: Annotated[
|
|
791
|
+
Optional[str], typer.Option("--service-description", help="service description")
|
|
792
|
+
] = None,
|
|
793
|
+
service_title: Annotated[
|
|
794
|
+
Optional[str],
|
|
795
|
+
typer.Option("--service-title", help="a display name for the service"),
|
|
796
|
+
] = None,
|
|
797
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
798
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
799
|
+
rules_file: Optional[str] = None,
|
|
800
|
+
require_toolkit: Annotated[
|
|
801
|
+
List[str],
|
|
802
|
+
typer.Option(
|
|
803
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
804
|
+
),
|
|
805
|
+
] = [],
|
|
806
|
+
require_schema: Annotated[
|
|
807
|
+
List[str],
|
|
808
|
+
typer.Option(
|
|
809
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
810
|
+
),
|
|
811
|
+
] = [],
|
|
812
|
+
toolkit: Annotated[
|
|
813
|
+
List[str],
|
|
814
|
+
typer.Option(
|
|
815
|
+
"--toolkit", "-t", help="the name or url of a required toolkit", hidden=True
|
|
816
|
+
),
|
|
817
|
+
] = [],
|
|
818
|
+
schema: Annotated[
|
|
819
|
+
List[str],
|
|
820
|
+
typer.Option(
|
|
821
|
+
"--schema", "-s", help="the name or url of a required schema", hidden=True
|
|
822
|
+
),
|
|
235
823
|
] = [],
|
|
236
824
|
model: Annotated[
|
|
237
825
|
str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
|
|
238
|
-
] = "gpt-5",
|
|
239
|
-
|
|
826
|
+
] = "gpt-5.2",
|
|
827
|
+
require_shell: Annotated[
|
|
828
|
+
Optional[bool],
|
|
829
|
+
typer.Option(..., help="Enable function shell tool calling"),
|
|
830
|
+
] = False,
|
|
831
|
+
require_local_shell: Annotated[
|
|
240
832
|
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
241
833
|
] = False,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
834
|
+
require_web_search: Annotated[
|
|
835
|
+
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
836
|
+
] = False,
|
|
837
|
+
require_apply_patch: Annotated[
|
|
838
|
+
Optional[bool],
|
|
839
|
+
typer.Option(..., help="Enable apply patch tool calling"),
|
|
840
|
+
] = False,
|
|
841
|
+
host: Annotated[
|
|
842
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
843
|
+
] = None,
|
|
844
|
+
port: Annotated[
|
|
845
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
846
|
+
] = None,
|
|
847
|
+
path: Annotated[
|
|
848
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
849
|
+
] = None,
|
|
850
|
+
queue: Annotated[
|
|
851
|
+
Optional[str], typer.Option(..., help="the name of the mail queue")
|
|
852
|
+
] = None,
|
|
246
853
|
email_address: Annotated[
|
|
247
854
|
str, typer.Option(..., help="the email address of the agent")
|
|
248
855
|
],
|
|
856
|
+
toolkit_name: Annotated[
|
|
857
|
+
Optional[str],
|
|
858
|
+
typer.Option(..., help="the name of a toolkit to expose mail operations"),
|
|
859
|
+
] = None,
|
|
860
|
+
room_rules: Annotated[
|
|
861
|
+
List[str],
|
|
862
|
+
typer.Option(
|
|
863
|
+
"--room-rules",
|
|
864
|
+
"-rr",
|
|
865
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
866
|
+
),
|
|
867
|
+
] = [],
|
|
868
|
+
whitelist: Annotated[
|
|
869
|
+
List[str],
|
|
870
|
+
typer.Option(
|
|
871
|
+
"--whitelist",
|
|
872
|
+
help="an email to whitelist",
|
|
873
|
+
),
|
|
874
|
+
] = [],
|
|
875
|
+
require_storage: Annotated[
|
|
876
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit")
|
|
877
|
+
] = False,
|
|
878
|
+
require_read_only_storage: Annotated[
|
|
879
|
+
Optional[bool],
|
|
880
|
+
typer.Option(..., help="Enable read only storage toolkit"),
|
|
881
|
+
] = False,
|
|
882
|
+
require_time: Annotated[
|
|
883
|
+
bool,
|
|
884
|
+
typer.Option(
|
|
885
|
+
...,
|
|
886
|
+
help="Enable time/datetime tools",
|
|
887
|
+
),
|
|
888
|
+
] = True,
|
|
889
|
+
require_uuid: Annotated[
|
|
890
|
+
bool,
|
|
891
|
+
typer.Option(
|
|
892
|
+
...,
|
|
893
|
+
help="Enable UUID generation tools",
|
|
894
|
+
),
|
|
895
|
+
] = False,
|
|
896
|
+
database_namespace: Annotated[
|
|
897
|
+
Optional[str],
|
|
898
|
+
typer.Option(..., help="Use a specific database namespace"),
|
|
899
|
+
] = None,
|
|
900
|
+
require_table_read: Annotated[
|
|
901
|
+
list[str],
|
|
902
|
+
typer.Option(..., help="Enable table read tools for a specific table"),
|
|
903
|
+
] = [],
|
|
904
|
+
require_table_write: Annotated[
|
|
905
|
+
list[str],
|
|
906
|
+
typer.Option(..., help="Enable table write tools for a specific table"),
|
|
907
|
+
] = [],
|
|
908
|
+
require_computer_use: Annotated[
|
|
909
|
+
Optional[bool],
|
|
910
|
+
typer.Option(
|
|
911
|
+
...,
|
|
912
|
+
help="Enable computer use (requires computer-use-preview model)",
|
|
913
|
+
hidden=True,
|
|
914
|
+
),
|
|
915
|
+
] = False,
|
|
916
|
+
reply_all: Annotated[
|
|
917
|
+
bool, typer.Option(help="Reply-all when responding to emails")
|
|
918
|
+
] = False,
|
|
919
|
+
enable_attachments: Annotated[
|
|
920
|
+
bool, typer.Option(help="Allow downloading and processing email attachments")
|
|
921
|
+
] = False,
|
|
922
|
+
working_directory: Annotated[
|
|
923
|
+
Optional[str],
|
|
924
|
+
typer.Option(..., help="The default working directory for shell commands"),
|
|
925
|
+
] = None,
|
|
926
|
+
skill_dir: Annotated[
|
|
927
|
+
list[str],
|
|
928
|
+
typer.Option(..., help="an agent skills directory"),
|
|
929
|
+
] = [],
|
|
930
|
+
llm_participant: Annotated[
|
|
931
|
+
Optional[str],
|
|
932
|
+
typer.Option(..., help="Delegate LLM interactions to a remote participant"),
|
|
933
|
+
] = None,
|
|
934
|
+
shell_image: Annotated[
|
|
935
|
+
Optional[str],
|
|
936
|
+
typer.Option(..., help="an image tag to use to run shell commands in"),
|
|
937
|
+
] = None,
|
|
938
|
+
delegate_shell_token: Annotated[
|
|
939
|
+
Optional[bool],
|
|
940
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
941
|
+
] = False,
|
|
942
|
+
log_llm_requests: Annotated[
|
|
943
|
+
Optional[bool],
|
|
944
|
+
typer.Option(..., help="log all requests to the llm"),
|
|
945
|
+
] = False,
|
|
249
946
|
):
|
|
250
|
-
|
|
947
|
+
service = get_service(host=host, port=port)
|
|
948
|
+
if path is None:
|
|
949
|
+
path = "/agent"
|
|
950
|
+
i = 0
|
|
951
|
+
while service.has_path(path):
|
|
952
|
+
i += 1
|
|
953
|
+
path = f"/agent{i}"
|
|
954
|
+
|
|
955
|
+
service.agents.append(
|
|
956
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "MailBot"})
|
|
957
|
+
)
|
|
251
958
|
|
|
252
|
-
service = ServiceHost(host=host, port=port)
|
|
253
959
|
service.add_path(
|
|
960
|
+
identity=agent_name,
|
|
254
961
|
path=path,
|
|
255
962
|
cls=build_mailbot(
|
|
256
963
|
queue=queue,
|
|
257
964
|
computer_use=None,
|
|
258
965
|
model=model,
|
|
259
|
-
local_shell=
|
|
260
|
-
|
|
966
|
+
local_shell=require_local_shell,
|
|
967
|
+
web_search=require_web_search,
|
|
261
968
|
rule=rule,
|
|
262
|
-
|
|
263
|
-
|
|
969
|
+
schema=require_schema + schema,
|
|
970
|
+
toolkit=require_toolkit + toolkit,
|
|
264
971
|
image_generation=None,
|
|
265
972
|
rules_file=rules_file,
|
|
266
973
|
email_address=email_address,
|
|
974
|
+
toolkit_name=toolkit_name,
|
|
975
|
+
room_rules_paths=room_rules,
|
|
976
|
+
whitelist=whitelist,
|
|
977
|
+
require_shell=require_shell,
|
|
978
|
+
require_apply_patch=require_apply_patch,
|
|
979
|
+
require_storage=require_storage,
|
|
980
|
+
require_read_only_storage=require_read_only_storage,
|
|
981
|
+
require_time=require_time,
|
|
982
|
+
require_uuid=require_uuid,
|
|
983
|
+
require_table_read=require_table_read,
|
|
984
|
+
require_table_write=require_table_write,
|
|
985
|
+
require_computer_use=require_computer_use,
|
|
986
|
+
reply_all=reply_all,
|
|
987
|
+
database_namespace=database_namespace,
|
|
988
|
+
enable_attachments=enable_attachments,
|
|
989
|
+
working_directory=working_directory,
|
|
990
|
+
skill_dirs=skill_dir,
|
|
991
|
+
shell_image=shell_image,
|
|
992
|
+
llm_participant=llm_participant,
|
|
993
|
+
delegate_shell_token=delegate_shell_token,
|
|
994
|
+
log_llm_requests=log_llm_requests,
|
|
267
995
|
),
|
|
268
996
|
)
|
|
269
997
|
|
|
270
|
-
|
|
998
|
+
spec = service_specs()[0]
|
|
999
|
+
spec.metadata.annotations = {
|
|
1000
|
+
"meshagent.service.id": service_name,
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
spec.metadata.name = service_name
|
|
1004
|
+
spec.metadata.description = service_description
|
|
1005
|
+
spec.container.image = (
|
|
1006
|
+
"us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz"
|
|
1007
|
+
)
|
|
1008
|
+
spec.container.command = shlex.join(
|
|
1009
|
+
["meshagent", "mailbot", "service", *cleanup_args(sys.argv[2:])]
|
|
1010
|
+
)
|
|
1011
|
+
|
|
1012
|
+
print(yaml.dump(spec.model_dump(mode="json", exclude_none=True), sort_keys=False))
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
@app.async_command("deploy")
|
|
1016
|
+
async def deploy(
|
|
1017
|
+
*,
|
|
1018
|
+
service_name: Annotated[str, typer.Option("--service-name", help="service name")],
|
|
1019
|
+
service_description: Annotated[
|
|
1020
|
+
Optional[str], typer.Option("--service-description", help="service description")
|
|
1021
|
+
] = None,
|
|
1022
|
+
service_title: Annotated[
|
|
1023
|
+
Optional[str],
|
|
1024
|
+
typer.Option("--service-title", help="a display name for the service"),
|
|
1025
|
+
] = None,
|
|
1026
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
1027
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
1028
|
+
rules_file: Optional[str] = None,
|
|
1029
|
+
require_toolkit: Annotated[
|
|
1030
|
+
List[str],
|
|
1031
|
+
typer.Option(
|
|
1032
|
+
"--require-toolkit", "-rt", help="the name or url of a required toolkit"
|
|
1033
|
+
),
|
|
1034
|
+
] = [],
|
|
1035
|
+
require_schema: Annotated[
|
|
1036
|
+
List[str],
|
|
1037
|
+
typer.Option(
|
|
1038
|
+
"--require-schema", "-rs", help="the name or url of a required schema"
|
|
1039
|
+
),
|
|
1040
|
+
] = [],
|
|
1041
|
+
toolkit: Annotated[
|
|
1042
|
+
List[str],
|
|
1043
|
+
typer.Option(
|
|
1044
|
+
"--toolkit", "-t", help="the name or url of a required toolkit", hidden=True
|
|
1045
|
+
),
|
|
1046
|
+
] = [],
|
|
1047
|
+
schema: Annotated[
|
|
1048
|
+
List[str],
|
|
1049
|
+
typer.Option(
|
|
1050
|
+
"--schema", "-s", help="the name or url of a required schema", hidden=True
|
|
1051
|
+
),
|
|
1052
|
+
] = [],
|
|
1053
|
+
model: Annotated[
|
|
1054
|
+
str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
|
|
1055
|
+
] = "gpt-5.2",
|
|
1056
|
+
require_shell: Annotated[
|
|
1057
|
+
Optional[bool],
|
|
1058
|
+
typer.Option(..., help="Enable function shell tool calling"),
|
|
1059
|
+
] = False,
|
|
1060
|
+
require_local_shell: Annotated[
|
|
1061
|
+
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
1062
|
+
] = False,
|
|
1063
|
+
require_web_search: Annotated[
|
|
1064
|
+
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
1065
|
+
] = False,
|
|
1066
|
+
require_apply_patch: Annotated[
|
|
1067
|
+
Optional[bool],
|
|
1068
|
+
typer.Option(..., help="Enable apply patch tool calling"),
|
|
1069
|
+
] = False,
|
|
1070
|
+
host: Annotated[
|
|
1071
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
1072
|
+
] = None,
|
|
1073
|
+
port: Annotated[
|
|
1074
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
1075
|
+
] = None,
|
|
1076
|
+
path: Annotated[
|
|
1077
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
1078
|
+
] = None,
|
|
1079
|
+
queue: Annotated[
|
|
1080
|
+
Optional[str], typer.Option(..., help="the name of the mail queue")
|
|
1081
|
+
] = None,
|
|
1082
|
+
email_address: Annotated[
|
|
1083
|
+
str, typer.Option(..., help="the email address of the agent")
|
|
1084
|
+
],
|
|
1085
|
+
toolkit_name: Annotated[
|
|
1086
|
+
Optional[str],
|
|
1087
|
+
typer.Option(..., help="the name of a toolkit to expose mail operations"),
|
|
1088
|
+
] = None,
|
|
1089
|
+
room_rules: Annotated[
|
|
1090
|
+
List[str],
|
|
1091
|
+
typer.Option(
|
|
1092
|
+
"--room-rules",
|
|
1093
|
+
"-rr",
|
|
1094
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
1095
|
+
),
|
|
1096
|
+
] = [],
|
|
1097
|
+
whitelist: Annotated[
|
|
1098
|
+
List[str],
|
|
1099
|
+
typer.Option(
|
|
1100
|
+
"--whitelist",
|
|
1101
|
+
help="an email to whitelist",
|
|
1102
|
+
),
|
|
1103
|
+
] = [],
|
|
1104
|
+
require_storage: Annotated[
|
|
1105
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit")
|
|
1106
|
+
] = False,
|
|
1107
|
+
require_read_only_storage: Annotated[
|
|
1108
|
+
Optional[bool],
|
|
1109
|
+
typer.Option(..., help="Enable read only storage toolkit"),
|
|
1110
|
+
] = False,
|
|
1111
|
+
require_time: Annotated[
|
|
1112
|
+
bool,
|
|
1113
|
+
typer.Option(
|
|
1114
|
+
...,
|
|
1115
|
+
help="Enable time/datetime tools",
|
|
1116
|
+
),
|
|
1117
|
+
] = True,
|
|
1118
|
+
require_uuid: Annotated[
|
|
1119
|
+
bool,
|
|
1120
|
+
typer.Option(
|
|
1121
|
+
...,
|
|
1122
|
+
help="Enable UUID generation tools",
|
|
1123
|
+
),
|
|
1124
|
+
] = False,
|
|
1125
|
+
database_namespace: Annotated[
|
|
1126
|
+
Optional[str],
|
|
1127
|
+
typer.Option(..., help="Use a specific database namespace"),
|
|
1128
|
+
] = None,
|
|
1129
|
+
require_table_read: Annotated[
|
|
1130
|
+
list[str],
|
|
1131
|
+
typer.Option(..., help="Enable table read tools for a specific table"),
|
|
1132
|
+
] = [],
|
|
1133
|
+
require_table_write: Annotated[
|
|
1134
|
+
list[str],
|
|
1135
|
+
typer.Option(..., help="Enable table write tools for a specific table"),
|
|
1136
|
+
] = [],
|
|
1137
|
+
require_computer_use: Annotated[
|
|
1138
|
+
Optional[bool],
|
|
1139
|
+
typer.Option(
|
|
1140
|
+
...,
|
|
1141
|
+
help="Enable computer use (requires computer-use-preview model)",
|
|
1142
|
+
hidden=True,
|
|
1143
|
+
),
|
|
1144
|
+
] = False,
|
|
1145
|
+
reply_all: Annotated[
|
|
1146
|
+
bool, typer.Option(help="Reply-all when responding to emails")
|
|
1147
|
+
] = False,
|
|
1148
|
+
enable_attachments: Annotated[
|
|
1149
|
+
bool, typer.Option(help="Allow downloading and processing email attachments")
|
|
1150
|
+
] = False,
|
|
1151
|
+
working_directory: Annotated[
|
|
1152
|
+
Optional[str],
|
|
1153
|
+
typer.Option(..., help="The default working directory for shell commands"),
|
|
1154
|
+
] = None,
|
|
1155
|
+
skill_dir: Annotated[
|
|
1156
|
+
list[str],
|
|
1157
|
+
typer.Option(..., help="an agent skills directory"),
|
|
1158
|
+
] = [],
|
|
1159
|
+
llm_participant: Annotated[
|
|
1160
|
+
Optional[str],
|
|
1161
|
+
typer.Option(..., help="Delegate LLM interactions to a remote participant"),
|
|
1162
|
+
] = None,
|
|
1163
|
+
shell_image: Annotated[
|
|
1164
|
+
Optional[str],
|
|
1165
|
+
typer.Option(..., help="an image tag to use to run shell commands in"),
|
|
1166
|
+
] = None,
|
|
1167
|
+
delegate_shell_token: Annotated[
|
|
1168
|
+
Optional[bool],
|
|
1169
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
1170
|
+
] = False,
|
|
1171
|
+
log_llm_requests: Annotated[
|
|
1172
|
+
Optional[bool],
|
|
1173
|
+
typer.Option(..., help="log all requests to the llm"),
|
|
1174
|
+
] = False,
|
|
1175
|
+
project_id: ProjectIdOption,
|
|
1176
|
+
room: Annotated[
|
|
1177
|
+
Optional[str],
|
|
1178
|
+
typer.Option("--room", help="The name of a room to create the service for"),
|
|
1179
|
+
] = None,
|
|
1180
|
+
):
|
|
1181
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
1182
|
+
|
|
1183
|
+
service = get_service(host=host, port=port)
|
|
1184
|
+
if path is None:
|
|
1185
|
+
path = "/agent"
|
|
1186
|
+
i = 0
|
|
1187
|
+
while service.has_path(path):
|
|
1188
|
+
i += 1
|
|
1189
|
+
path = f"/agent{i}"
|
|
1190
|
+
|
|
1191
|
+
service.agents.append(
|
|
1192
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "MailBot"})
|
|
1193
|
+
)
|
|
1194
|
+
|
|
1195
|
+
service.add_path(
|
|
1196
|
+
identity=agent_name,
|
|
1197
|
+
path=path,
|
|
1198
|
+
cls=build_mailbot(
|
|
1199
|
+
queue=queue,
|
|
1200
|
+
computer_use=None,
|
|
1201
|
+
model=model,
|
|
1202
|
+
local_shell=require_local_shell,
|
|
1203
|
+
web_search=require_web_search,
|
|
1204
|
+
rule=rule,
|
|
1205
|
+
schema=require_schema + schema,
|
|
1206
|
+
toolkit=require_toolkit + toolkit,
|
|
1207
|
+
image_generation=None,
|
|
1208
|
+
rules_file=rules_file,
|
|
1209
|
+
email_address=email_address,
|
|
1210
|
+
toolkit_name=toolkit_name,
|
|
1211
|
+
room_rules_paths=room_rules,
|
|
1212
|
+
whitelist=whitelist,
|
|
1213
|
+
require_shell=require_shell,
|
|
1214
|
+
require_apply_patch=require_apply_patch,
|
|
1215
|
+
require_storage=require_storage,
|
|
1216
|
+
require_read_only_storage=require_read_only_storage,
|
|
1217
|
+
require_time=require_time,
|
|
1218
|
+
require_uuid=require_uuid,
|
|
1219
|
+
require_table_read=require_table_read,
|
|
1220
|
+
require_table_write=require_table_write,
|
|
1221
|
+
require_computer_use=require_computer_use,
|
|
1222
|
+
reply_all=reply_all,
|
|
1223
|
+
database_namespace=database_namespace,
|
|
1224
|
+
enable_attachments=enable_attachments,
|
|
1225
|
+
working_directory=working_directory,
|
|
1226
|
+
skill_dirs=skill_dir,
|
|
1227
|
+
shell_image=shell_image,
|
|
1228
|
+
llm_participant=llm_participant,
|
|
1229
|
+
delegate_shell_token=delegate_shell_token,
|
|
1230
|
+
log_llm_requests=log_llm_requests,
|
|
1231
|
+
),
|
|
1232
|
+
)
|
|
1233
|
+
|
|
1234
|
+
spec = service_specs()[0]
|
|
1235
|
+
spec.metadata.annotations = {
|
|
1236
|
+
"meshagent.service.id": service_name,
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
spec.metadata.name = service_name
|
|
1240
|
+
spec.metadata.description = service_description
|
|
1241
|
+
spec.container.image = (
|
|
1242
|
+
"us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz"
|
|
1243
|
+
)
|
|
1244
|
+
spec.container.command = shlex.join(
|
|
1245
|
+
["meshagent", "mailbot", *cleanup_args(sys.argv[:2])]
|
|
1246
|
+
)
|
|
1247
|
+
|
|
1248
|
+
client = await get_client()
|
|
1249
|
+
try:
|
|
1250
|
+
id = None
|
|
1251
|
+
try:
|
|
1252
|
+
if id is None:
|
|
1253
|
+
if room is None:
|
|
1254
|
+
services = await client.list_services(project_id=project_id)
|
|
1255
|
+
else:
|
|
1256
|
+
services = await client.list_room_services(
|
|
1257
|
+
project_id=project_id, room_name=room
|
|
1258
|
+
)
|
|
1259
|
+
|
|
1260
|
+
for s in services:
|
|
1261
|
+
if s.metadata.name == spec.metadata.name:
|
|
1262
|
+
id = s.id
|
|
1263
|
+
|
|
1264
|
+
if id is None:
|
|
1265
|
+
if room is None:
|
|
1266
|
+
id = await client.create_service(
|
|
1267
|
+
project_id=project_id, service=spec
|
|
1268
|
+
)
|
|
1269
|
+
else:
|
|
1270
|
+
id = await client.create_room_service(
|
|
1271
|
+
project_id=project_id, service=spec, room_name=room
|
|
1272
|
+
)
|
|
1273
|
+
|
|
1274
|
+
else:
|
|
1275
|
+
spec.id = id
|
|
1276
|
+
if room is None:
|
|
1277
|
+
await client.update_service(
|
|
1278
|
+
project_id=project_id, service_id=id, service=spec
|
|
1279
|
+
)
|
|
1280
|
+
else:
|
|
1281
|
+
await client.update_room_service(
|
|
1282
|
+
project_id=project_id,
|
|
1283
|
+
service_id=id,
|
|
1284
|
+
service=spec,
|
|
1285
|
+
room_name=room,
|
|
1286
|
+
)
|
|
1287
|
+
|
|
1288
|
+
except ConflictError:
|
|
1289
|
+
print(f"[red]Service name already in use: {spec.metadata.name}[/red]")
|
|
1290
|
+
raise typer.Exit(code=1)
|
|
1291
|
+
else:
|
|
1292
|
+
print(f"[green]Deployed service:[/] {id}")
|
|
1293
|
+
|
|
1294
|
+
finally:
|
|
1295
|
+
await client.close()
|