meshagent-cli 0.21.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 +8 -2
- meshagent/cli/call.py +15 -28
- meshagent/cli/chatbot.py +580 -76
- meshagent/cli/cli.py +3 -3
- meshagent/cli/helper.py +40 -2
- meshagent/cli/helpers.py +0 -3
- meshagent/cli/host.py +4 -0
- meshagent/cli/mailbot.py +137 -76
- meshagent/cli/meeting_transcriber.py +19 -11
- meshagent/cli/messaging.py +1 -4
- meshagent/cli/multi.py +53 -98
- meshagent/cli/oauth2.py +164 -35
- meshagent/cli/room.py +6 -2
- meshagent/cli/services.py +238 -15
- meshagent/cli/sync.py +434 -0
- meshagent/cli/task_runner.py +625 -78
- meshagent/cli/version.py +1 -1
- meshagent/cli/voicebot.py +54 -34
- meshagent/cli/worker.py +151 -75
- {meshagent_cli-0.21.0.dist-info → meshagent_cli-0.23.0.dist-info}/METADATA +13 -11
- meshagent_cli-0.23.0.dist-info/RECORD +45 -0
- {meshagent_cli-0.21.0.dist-info → meshagent_cli-0.23.0.dist-info}/WHEEL +1 -1
- meshagent_cli-0.21.0.dist-info/RECORD +0 -44
- {meshagent_cli-0.21.0.dist-info → meshagent_cli-0.23.0.dist-info}/entry_points.txt +0 -0
- {meshagent_cli-0.21.0.dist-info → meshagent_cli-0.23.0.dist-info}/top_level.txt +0 -0
meshagent/cli/task_runner.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import typer
|
|
2
2
|
import json
|
|
3
|
+
import os
|
|
3
4
|
from rich import print
|
|
4
5
|
from typing import Annotated, Optional
|
|
5
6
|
from meshagent.tools import Toolkit
|
|
@@ -21,6 +22,7 @@ from meshagent.api import (
|
|
|
21
22
|
ParticipantToken,
|
|
22
23
|
ApiScope,
|
|
23
24
|
RoomException,
|
|
25
|
+
RemoteParticipant,
|
|
24
26
|
)
|
|
25
27
|
from meshagent.api.helpers import meshagent_base_url, websocket_room_url
|
|
26
28
|
from meshagent.cli import async_typer
|
|
@@ -29,9 +31,11 @@ from meshagent.cli.helper import (
|
|
|
29
31
|
resolve_project_id,
|
|
30
32
|
resolve_room,
|
|
31
33
|
resolve_key,
|
|
34
|
+
cleanup_args,
|
|
32
35
|
)
|
|
33
36
|
|
|
34
37
|
from meshagent.openai import OpenAIResponsesAdapter
|
|
38
|
+
from meshagent.anthropic import AnthropicOpenAIResponsesStreamAdapter
|
|
35
39
|
|
|
36
40
|
from typing import List
|
|
37
41
|
from pathlib import Path
|
|
@@ -55,17 +59,24 @@ from meshagent.openai.tools.responses_adapter import (
|
|
|
55
59
|
ImageGenerationTool,
|
|
56
60
|
)
|
|
57
61
|
|
|
62
|
+
from meshagent.cli.host import get_service, run_services, get_deferred, service_specs
|
|
58
63
|
from meshagent.tools.database import DatabaseToolkitBuilder, DatabaseToolkitConfig
|
|
59
64
|
from meshagent.agents.adapter import MessageStreamLLMAdapter
|
|
60
65
|
from meshagent.agents.context import AgentCallContext
|
|
61
66
|
|
|
62
67
|
from meshagent.api import RequiredToolkit, RequiredSchema
|
|
63
|
-
from meshagent.api.
|
|
68
|
+
from meshagent.api.specs.service import AgentSpec, ANNOTATION_AGENT_TYPE
|
|
64
69
|
import logging
|
|
65
70
|
import os.path
|
|
66
71
|
|
|
67
72
|
from urllib.request import urlopen
|
|
68
73
|
|
|
74
|
+
import yaml
|
|
75
|
+
import shlex
|
|
76
|
+
import sys
|
|
77
|
+
|
|
78
|
+
from meshagent.api.client import ConflictError
|
|
79
|
+
|
|
69
80
|
logger = logging.getLogger("taskrunner")
|
|
70
81
|
|
|
71
82
|
app = async_typer.AsyncTyper(help="Join a taskrunner to a room")
|
|
@@ -74,7 +85,6 @@ app = async_typer.AsyncTyper(help="Join a taskrunner to a room")
|
|
|
74
85
|
def build_task_runner(
|
|
75
86
|
*,
|
|
76
87
|
model: str,
|
|
77
|
-
agent_name: str,
|
|
78
88
|
rule: List[str],
|
|
79
89
|
toolkit: List[str],
|
|
80
90
|
schema: List[str],
|
|
@@ -107,6 +117,7 @@ def build_task_runner(
|
|
|
107
117
|
title: Optional[str] = None,
|
|
108
118
|
description: Optional[str] = None,
|
|
109
119
|
shell_image: Optional[str] = None,
|
|
120
|
+
delegate_shell_token: Optional[bool] = None,
|
|
110
121
|
):
|
|
111
122
|
output_schema = None
|
|
112
123
|
if output_schema_str is not None:
|
|
@@ -153,15 +164,15 @@ def build_task_runner(
|
|
|
153
164
|
participant_name=llm_participant,
|
|
154
165
|
)
|
|
155
166
|
else:
|
|
156
|
-
|
|
157
|
-
model=model
|
|
158
|
-
|
|
167
|
+
if model.startswith("claude-"):
|
|
168
|
+
llm_adapter = AnthropicOpenAIResponsesStreamAdapter(model=model)
|
|
169
|
+
else:
|
|
170
|
+
llm_adapter = OpenAIResponsesAdapter(model=model)
|
|
159
171
|
|
|
160
172
|
class CustomTaskRunner(BaseClass):
|
|
161
173
|
def __init__(self):
|
|
162
174
|
super().__init__(
|
|
163
175
|
llm_adapter=llm_adapter,
|
|
164
|
-
name=agent_name,
|
|
165
176
|
requires=requirements,
|
|
166
177
|
toolkits=toolkits,
|
|
167
178
|
rules=rule if len(rule) > 0 else None,
|
|
@@ -179,13 +190,20 @@ def build_task_runner(
|
|
|
179
190
|
for p in room_rules_path:
|
|
180
191
|
await self._load_room_rules(path=p)
|
|
181
192
|
|
|
193
|
+
async def init_chat_context(self):
|
|
194
|
+
from meshagent.cli.helper import init_context_from_spec
|
|
195
|
+
|
|
196
|
+
context = await super().init_chat_context()
|
|
197
|
+
await init_context_from_spec(context)
|
|
198
|
+
|
|
199
|
+
return context
|
|
200
|
+
|
|
182
201
|
async def _load_room_rules(
|
|
183
202
|
self,
|
|
184
203
|
*,
|
|
185
204
|
path: str,
|
|
186
|
-
|
|
205
|
+
participant: Optional[RemoteParticipant] = None,
|
|
187
206
|
):
|
|
188
|
-
participant = context.caller
|
|
189
207
|
rules = []
|
|
190
208
|
try:
|
|
191
209
|
room_rules = await self.room.storage.download(path=path)
|
|
@@ -229,7 +247,9 @@ def build_task_runner(
|
|
|
229
247
|
|
|
230
248
|
if room_rules_path is not None:
|
|
231
249
|
for p in room_rules_path:
|
|
232
|
-
rules.extend(
|
|
250
|
+
rules.extend(
|
|
251
|
+
await self._load_room_rules(path=p, participant=context.caller)
|
|
252
|
+
)
|
|
233
253
|
|
|
234
254
|
logging.info(f"using rules {rules}")
|
|
235
255
|
|
|
@@ -256,12 +276,17 @@ def build_task_runner(
|
|
|
256
276
|
)
|
|
257
277
|
)
|
|
258
278
|
|
|
279
|
+
env = {}
|
|
280
|
+
if delegate_shell_token:
|
|
281
|
+
env["MESHAGENT_TOKEN"] = self.room.protocol.token
|
|
282
|
+
|
|
259
283
|
if require_shell:
|
|
260
284
|
providers.append(
|
|
261
285
|
ShellTool(
|
|
262
286
|
working_directory=working_directory,
|
|
263
287
|
config=ShellConfig(name="shell"),
|
|
264
288
|
image=shell_image or "python:3.13",
|
|
289
|
+
env=env,
|
|
265
290
|
)
|
|
266
291
|
)
|
|
267
292
|
|
|
@@ -375,12 +400,14 @@ def build_task_runner(
|
|
|
375
400
|
|
|
376
401
|
|
|
377
402
|
@app.async_command("join")
|
|
378
|
-
async def
|
|
403
|
+
async def join(
|
|
379
404
|
*,
|
|
380
405
|
project_id: ProjectIdOption,
|
|
381
406
|
room: RoomOption,
|
|
382
407
|
role: str = "agent",
|
|
383
|
-
agent_name: Annotated[
|
|
408
|
+
agent_name: Annotated[
|
|
409
|
+
Optional[str], typer.Option(..., help="Name of the agent to call")
|
|
410
|
+
] = None,
|
|
384
411
|
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
385
412
|
room_rules: Annotated[
|
|
386
413
|
List[str],
|
|
@@ -476,6 +503,10 @@ async def make_call(
|
|
|
476
503
|
Optional[str],
|
|
477
504
|
typer.Option(..., help="The default working directory for shell commands"),
|
|
478
505
|
] = None,
|
|
506
|
+
delegate_shell_token: Annotated[
|
|
507
|
+
Optional[bool],
|
|
508
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
509
|
+
] = False,
|
|
479
510
|
key: Annotated[
|
|
480
511
|
str,
|
|
481
512
|
typer.Option("--key", help="an api key to sign the token with"),
|
|
@@ -513,79 +544,94 @@ async def make_call(
|
|
|
513
544
|
project_id = await resolve_project_id(project_id=project_id)
|
|
514
545
|
room = resolve_room(room)
|
|
515
546
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
547
|
+
jwt = os.getenv("MESHAGENT_TOKEN")
|
|
548
|
+
if jwt is None:
|
|
549
|
+
if agent_name is None:
|
|
550
|
+
print(
|
|
551
|
+
"[bold red]--agent-name must be specified when the MESHAGENT_TOKEN environment variable is not set[/bold red]"
|
|
552
|
+
)
|
|
553
|
+
raise typer.Exit(1)
|
|
519
554
|
|
|
520
|
-
|
|
555
|
+
token = ParticipantToken(
|
|
556
|
+
name=agent_name,
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
token.add_api_grant(ApiScope.agent_default())
|
|
521
560
|
|
|
522
|
-
|
|
523
|
-
|
|
561
|
+
token.add_role_grant(role=role)
|
|
562
|
+
token.add_room_grant(room)
|
|
524
563
|
|
|
525
|
-
|
|
564
|
+
jwt = token.to_jwt(api_key=key)
|
|
526
565
|
|
|
527
566
|
print("[bold green]Connecting to room...[/bold green]", flush=True)
|
|
528
|
-
|
|
529
|
-
protocol=WebSocketClientProtocol(
|
|
530
|
-
url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
|
|
531
|
-
token=jwt,
|
|
532
|
-
)
|
|
533
|
-
) as client:
|
|
534
|
-
requirements = []
|
|
567
|
+
requirements = []
|
|
535
568
|
|
|
536
|
-
|
|
537
|
-
|
|
569
|
+
for t in toolkit:
|
|
570
|
+
requirements.append(RequiredToolkit(name=t))
|
|
538
571
|
|
|
539
|
-
|
|
540
|
-
|
|
572
|
+
for t in schema:
|
|
573
|
+
requirements.append(RequiredSchema(name=t))
|
|
541
574
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
575
|
+
CustomTaskRunner = build_task_runner(
|
|
576
|
+
title=title,
|
|
577
|
+
description=description,
|
|
578
|
+
model=model,
|
|
579
|
+
local_shell=local_shell,
|
|
580
|
+
shell=shell,
|
|
581
|
+
apply_patch=apply_patch,
|
|
582
|
+
rule=rule,
|
|
583
|
+
toolkit=toolkit,
|
|
584
|
+
schema=schema,
|
|
585
|
+
rules_file=rules_file,
|
|
586
|
+
image_generation=image_generation,
|
|
587
|
+
web_search=web_search,
|
|
588
|
+
mcp=mcp,
|
|
589
|
+
storage=storage,
|
|
590
|
+
require_apply_patch=require_apply_patch,
|
|
591
|
+
require_web_search=require_web_search,
|
|
592
|
+
require_local_shell=require_local_shell,
|
|
593
|
+
require_shell=require_shell,
|
|
594
|
+
require_image_generation=require_image_generation,
|
|
595
|
+
require_mcp=require_mcp,
|
|
596
|
+
require_storage=require_storage,
|
|
597
|
+
require_table_read=require_table_read,
|
|
598
|
+
require_table_write=require_table_write,
|
|
599
|
+
require_read_only_storage=require_read_only_storage,
|
|
600
|
+
room_rules_path=room_rules,
|
|
601
|
+
require_document_authoring=require_document_authoring,
|
|
602
|
+
require_discovery=require_discovery,
|
|
603
|
+
working_directory=working_directory,
|
|
604
|
+
delegate_shell_token=delegate_shell_token,
|
|
605
|
+
llm_participant=llm_participant,
|
|
606
|
+
output_schema_str=output_schema,
|
|
607
|
+
output_schema_path=output_schema_path,
|
|
608
|
+
annotations=json.loads(annotations) if annotations != "" else {},
|
|
609
|
+
)
|
|
577
610
|
|
|
578
|
-
|
|
611
|
+
bot = CustomTaskRunner()
|
|
579
612
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
613
|
+
if get_deferred():
|
|
614
|
+
from meshagent.cli.host import agents
|
|
615
|
+
|
|
616
|
+
agents.append((bot, jwt))
|
|
617
|
+
else:
|
|
618
|
+
async with RoomClient(
|
|
619
|
+
protocol=WebSocketClientProtocol(
|
|
620
|
+
url=websocket_room_url(
|
|
621
|
+
room_name=room, base_url=meshagent_base_url()
|
|
622
|
+
),
|
|
623
|
+
token=jwt,
|
|
585
624
|
)
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
625
|
+
) as client:
|
|
626
|
+
await bot.start(room=client)
|
|
627
|
+
try:
|
|
628
|
+
print(
|
|
629
|
+
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]",
|
|
630
|
+
flush=True,
|
|
631
|
+
)
|
|
632
|
+
await client.protocol.wait_for_close()
|
|
633
|
+
except KeyboardInterrupt:
|
|
634
|
+
await bot.stop()
|
|
589
635
|
|
|
590
636
|
finally:
|
|
591
637
|
await account_client.close()
|
|
@@ -681,6 +727,10 @@ async def service(
|
|
|
681
727
|
Optional[str],
|
|
682
728
|
typer.Option(..., help="The default working directory for shell commands"),
|
|
683
729
|
] = None,
|
|
730
|
+
delegate_shell_token: Annotated[
|
|
731
|
+
Optional[bool],
|
|
732
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
733
|
+
] = False,
|
|
684
734
|
require_document_authoring: Annotated[
|
|
685
735
|
Optional[bool],
|
|
686
736
|
typer.Option(..., help="Enable document authoring", hidden=True),
|
|
@@ -702,8 +752,8 @@ async def service(
|
|
|
702
752
|
Optional[int], typer.Option(help="Port to bind the service on")
|
|
703
753
|
] = None,
|
|
704
754
|
path: Annotated[
|
|
705
|
-
str, typer.Option(help="HTTP path to mount the service at")
|
|
706
|
-
] =
|
|
755
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
756
|
+
] = None,
|
|
707
757
|
output_schema: Annotated[
|
|
708
758
|
Optional[str],
|
|
709
759
|
typer.Option(..., help="an output schema to use", hidden=True),
|
|
@@ -727,15 +777,26 @@ async def service(
|
|
|
727
777
|
):
|
|
728
778
|
print("[bold green]Connecting to room...[/bold green]", flush=True)
|
|
729
779
|
|
|
730
|
-
service =
|
|
780
|
+
service = get_service(host=host, port=port)
|
|
781
|
+
if path is None:
|
|
782
|
+
path = "/agent"
|
|
783
|
+
i = 0
|
|
784
|
+
while service.has_path(path):
|
|
785
|
+
i += 1
|
|
786
|
+
path = f"/agent{i}"
|
|
787
|
+
|
|
788
|
+
service.agents.append(
|
|
789
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "TaskRunner"})
|
|
790
|
+
)
|
|
791
|
+
|
|
731
792
|
service.add_path(
|
|
793
|
+
identity=agent_name,
|
|
732
794
|
path=path,
|
|
733
795
|
cls=build_task_runner(
|
|
734
796
|
model=model,
|
|
735
797
|
local_shell=local_shell,
|
|
736
798
|
shell=shell,
|
|
737
799
|
apply_patch=apply_patch,
|
|
738
|
-
agent_name=agent_name,
|
|
739
800
|
title=title,
|
|
740
801
|
description=description,
|
|
741
802
|
rule=rule,
|
|
@@ -758,6 +819,7 @@ async def service(
|
|
|
758
819
|
require_read_only_storage=require_read_only_storage,
|
|
759
820
|
room_rules_path=room_rules,
|
|
760
821
|
working_directory=working_directory,
|
|
822
|
+
delegate_shell_token=delegate_shell_token,
|
|
761
823
|
require_document_authoring=require_document_authoring,
|
|
762
824
|
require_discovery=require_discovery,
|
|
763
825
|
llm_participant=llm_participant,
|
|
@@ -767,4 +829,489 @@ async def service(
|
|
|
767
829
|
),
|
|
768
830
|
)
|
|
769
831
|
|
|
770
|
-
|
|
832
|
+
if not get_deferred():
|
|
833
|
+
await run_services()
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
@app.async_command("spec")
|
|
837
|
+
async def spec(
|
|
838
|
+
*,
|
|
839
|
+
service_name: Annotated[str, typer.Option("--service-name", help="service name")],
|
|
840
|
+
service_description: Annotated[
|
|
841
|
+
Optional[str], typer.Option("--service-description", help="service description")
|
|
842
|
+
] = None,
|
|
843
|
+
service_title: Annotated[
|
|
844
|
+
Optional[str],
|
|
845
|
+
typer.Option("--service-title", help="a display name for the service"),
|
|
846
|
+
] = None,
|
|
847
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
848
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
849
|
+
rules_file: Optional[str] = None,
|
|
850
|
+
room_rules: Annotated[
|
|
851
|
+
List[str],
|
|
852
|
+
typer.Option(
|
|
853
|
+
"--room-rules",
|
|
854
|
+
"-rr",
|
|
855
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
856
|
+
),
|
|
857
|
+
] = [],
|
|
858
|
+
toolkit: Annotated[
|
|
859
|
+
List[str],
|
|
860
|
+
typer.Option("--toolkit", "-t", help="the name or url of a required toolkit"),
|
|
861
|
+
] = [],
|
|
862
|
+
schema: Annotated[
|
|
863
|
+
List[str],
|
|
864
|
+
typer.Option("--schema", "-s", help="the name or url of a required schema"),
|
|
865
|
+
] = [],
|
|
866
|
+
model: Annotated[
|
|
867
|
+
str, typer.Option(..., help="Name of the LLM model to use for the task runner")
|
|
868
|
+
] = "gpt-5.2",
|
|
869
|
+
image_generation: Annotated[
|
|
870
|
+
Optional[str], typer.Option(..., help="Name of an image gen model")
|
|
871
|
+
] = None,
|
|
872
|
+
local_shell: Annotated[
|
|
873
|
+
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
874
|
+
] = False,
|
|
875
|
+
shell: Annotated[
|
|
876
|
+
Optional[bool], typer.Option(..., help="Enable function shell tool calling")
|
|
877
|
+
] = False,
|
|
878
|
+
apply_patch: Annotated[
|
|
879
|
+
Optional[bool], typer.Option(..., help="Enable apply patch tool")
|
|
880
|
+
] = False,
|
|
881
|
+
web_search: Annotated[
|
|
882
|
+
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
883
|
+
] = False,
|
|
884
|
+
mcp: Annotated[
|
|
885
|
+
Optional[bool], typer.Option(..., help="Enable mcp tool calling")
|
|
886
|
+
] = False,
|
|
887
|
+
storage: Annotated[
|
|
888
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit")
|
|
889
|
+
] = False,
|
|
890
|
+
require_image_generation: Annotated[
|
|
891
|
+
Optional[str], typer.Option(..., help="Name of an image gen model", hidden=True)
|
|
892
|
+
] = None,
|
|
893
|
+
require_local_shell: Annotated[
|
|
894
|
+
Optional[bool],
|
|
895
|
+
typer.Option(..., help="Enable local shell tool calling", hidden=True),
|
|
896
|
+
] = False,
|
|
897
|
+
require_shell: Annotated[
|
|
898
|
+
Optional[bool],
|
|
899
|
+
typer.Option(..., help="Enable function shell tool calling", hidden=True),
|
|
900
|
+
] = False,
|
|
901
|
+
require_apply_patch: Annotated[
|
|
902
|
+
Optional[bool], typer.Option(..., help="Enable apply patch tool", hidden=True)
|
|
903
|
+
] = False,
|
|
904
|
+
require_web_search: Annotated[
|
|
905
|
+
Optional[bool],
|
|
906
|
+
typer.Option(..., help="Enable web search tool calling", hidden=True),
|
|
907
|
+
] = False,
|
|
908
|
+
require_mcp: Annotated[
|
|
909
|
+
Optional[bool], typer.Option(..., help="Enable mcp tool calling", hidden=True)
|
|
910
|
+
] = False,
|
|
911
|
+
require_storage: Annotated[
|
|
912
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit", hidden=True)
|
|
913
|
+
] = False,
|
|
914
|
+
require_table_read: Annotated[
|
|
915
|
+
list[str],
|
|
916
|
+
typer.Option(
|
|
917
|
+
..., help="Enable table read tools for a specific table", hidden=True
|
|
918
|
+
),
|
|
919
|
+
] = [],
|
|
920
|
+
require_table_write: Annotated[
|
|
921
|
+
list[str],
|
|
922
|
+
typer.Option(
|
|
923
|
+
..., help="Enable table write tools for a specific table", hidden=True
|
|
924
|
+
),
|
|
925
|
+
] = [],
|
|
926
|
+
require_read_only_storage: Annotated[
|
|
927
|
+
Optional[bool],
|
|
928
|
+
typer.Option(..., help="Enable read only storage toolkit", hidden=True),
|
|
929
|
+
] = False,
|
|
930
|
+
working_directory: Annotated[
|
|
931
|
+
Optional[str],
|
|
932
|
+
typer.Option(..., help="The default working directory for shell commands"),
|
|
933
|
+
] = None,
|
|
934
|
+
delegate_shell_token: Annotated[
|
|
935
|
+
Optional[bool],
|
|
936
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
937
|
+
] = False,
|
|
938
|
+
require_document_authoring: Annotated[
|
|
939
|
+
Optional[bool],
|
|
940
|
+
typer.Option(..., help="Enable document authoring", hidden=True),
|
|
941
|
+
] = False,
|
|
942
|
+
require_discovery: Annotated[
|
|
943
|
+
Optional[bool],
|
|
944
|
+
typer.Option(..., help="Enable discovery of agents and tools", hidden=True),
|
|
945
|
+
] = False,
|
|
946
|
+
llm_participant: Annotated[
|
|
947
|
+
Optional[str],
|
|
948
|
+
typer.Option(
|
|
949
|
+
..., help="Delegate LLM interactions to a remote participant", hidden=True
|
|
950
|
+
),
|
|
951
|
+
] = None,
|
|
952
|
+
host: Annotated[
|
|
953
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
954
|
+
] = None,
|
|
955
|
+
port: Annotated[
|
|
956
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
957
|
+
] = None,
|
|
958
|
+
path: Annotated[
|
|
959
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
960
|
+
] = None,
|
|
961
|
+
output_schema: Annotated[
|
|
962
|
+
Optional[str],
|
|
963
|
+
typer.Option(..., help="an output schema to use", hidden=True),
|
|
964
|
+
] = None,
|
|
965
|
+
output_schema_path: Annotated[
|
|
966
|
+
Optional[str],
|
|
967
|
+
typer.Option(..., help="the path or url to output schema to use", hidden=True),
|
|
968
|
+
] = None,
|
|
969
|
+
annotations: Annotated[
|
|
970
|
+
str,
|
|
971
|
+
typer.Option(
|
|
972
|
+
"--annotations", "-a", help='annotations in json format {"name":"value"}'
|
|
973
|
+
),
|
|
974
|
+
] = '{"meshagent.task-runner.attachment-format":"tar"}',
|
|
975
|
+
title: Annotated[
|
|
976
|
+
Optional[str], typer.Option(..., help="a friendly name for the task runner")
|
|
977
|
+
] = None,
|
|
978
|
+
description: Annotated[
|
|
979
|
+
Optional[str], typer.Option(..., help="a description for the task runner")
|
|
980
|
+
] = None,
|
|
981
|
+
):
|
|
982
|
+
service = get_service(host=host, port=port)
|
|
983
|
+
if path is None:
|
|
984
|
+
path = "/agent"
|
|
985
|
+
i = 0
|
|
986
|
+
while service.has_path(path):
|
|
987
|
+
i += 1
|
|
988
|
+
path = f"/agent{i}"
|
|
989
|
+
|
|
990
|
+
service.agents.append(
|
|
991
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "TaskRunner"})
|
|
992
|
+
)
|
|
993
|
+
|
|
994
|
+
service.add_path(
|
|
995
|
+
identity=agent_name,
|
|
996
|
+
path=path,
|
|
997
|
+
cls=build_task_runner(
|
|
998
|
+
model=model,
|
|
999
|
+
local_shell=local_shell,
|
|
1000
|
+
shell=shell,
|
|
1001
|
+
apply_patch=apply_patch,
|
|
1002
|
+
title=title,
|
|
1003
|
+
description=description,
|
|
1004
|
+
rule=rule,
|
|
1005
|
+
toolkit=toolkit,
|
|
1006
|
+
schema=schema,
|
|
1007
|
+
rules_file=rules_file,
|
|
1008
|
+
web_search=web_search,
|
|
1009
|
+
image_generation=image_generation,
|
|
1010
|
+
mcp=mcp,
|
|
1011
|
+
storage=storage,
|
|
1012
|
+
require_web_search=require_web_search,
|
|
1013
|
+
require_shell=require_shell,
|
|
1014
|
+
require_apply_patch=require_apply_patch,
|
|
1015
|
+
require_local_shell=require_local_shell,
|
|
1016
|
+
require_image_generation=require_image_generation,
|
|
1017
|
+
require_mcp=require_mcp,
|
|
1018
|
+
require_storage=require_storage,
|
|
1019
|
+
require_table_write=require_table_write,
|
|
1020
|
+
require_table_read=require_table_read,
|
|
1021
|
+
require_read_only_storage=require_read_only_storage,
|
|
1022
|
+
room_rules_path=room_rules,
|
|
1023
|
+
working_directory=working_directory,
|
|
1024
|
+
delegate_shell_token=delegate_shell_token,
|
|
1025
|
+
require_document_authoring=require_document_authoring,
|
|
1026
|
+
require_discovery=require_discovery,
|
|
1027
|
+
llm_participant=llm_participant,
|
|
1028
|
+
output_schema_str=output_schema,
|
|
1029
|
+
output_schema_path=output_schema_path,
|
|
1030
|
+
annotations=json.loads(annotations) if annotations != "" else {},
|
|
1031
|
+
),
|
|
1032
|
+
)
|
|
1033
|
+
|
|
1034
|
+
spec = service_specs()[0]
|
|
1035
|
+
spec.metadata.annotations = {
|
|
1036
|
+
"meshagent.service.id": service_name,
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
spec.metadata.name = service_name
|
|
1040
|
+
spec.metadata.description = service_description
|
|
1041
|
+
spec.container.image = (
|
|
1042
|
+
"us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz"
|
|
1043
|
+
)
|
|
1044
|
+
spec.container.command = shlex.join(
|
|
1045
|
+
["meshagent", "task-runner", "service", *cleanup_args(sys.argv[2:])]
|
|
1046
|
+
)
|
|
1047
|
+
|
|
1048
|
+
print(yaml.dump(spec.model_dump(mode="json", exclude_none=True), sort_keys=False))
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
@app.async_command("deploy")
|
|
1052
|
+
async def deploy(
|
|
1053
|
+
*,
|
|
1054
|
+
service_name: Annotated[str, typer.Option("--service-name", help="service name")],
|
|
1055
|
+
service_description: Annotated[
|
|
1056
|
+
Optional[str], typer.Option("--service-description", help="service description")
|
|
1057
|
+
] = None,
|
|
1058
|
+
service_title: Annotated[
|
|
1059
|
+
Optional[str],
|
|
1060
|
+
typer.Option("--service-title", help="a display name for the service"),
|
|
1061
|
+
] = None,
|
|
1062
|
+
agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
|
|
1063
|
+
rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
|
|
1064
|
+
rules_file: Optional[str] = None,
|
|
1065
|
+
room_rules: Annotated[
|
|
1066
|
+
List[str],
|
|
1067
|
+
typer.Option(
|
|
1068
|
+
"--room-rules",
|
|
1069
|
+
"-rr",
|
|
1070
|
+
help="a path to a rules file within the room that can be used to customize the agent's behavior",
|
|
1071
|
+
),
|
|
1072
|
+
] = [],
|
|
1073
|
+
toolkit: Annotated[
|
|
1074
|
+
List[str],
|
|
1075
|
+
typer.Option("--toolkit", "-t", help="the name or url of a required toolkit"),
|
|
1076
|
+
] = [],
|
|
1077
|
+
schema: Annotated[
|
|
1078
|
+
List[str],
|
|
1079
|
+
typer.Option("--schema", "-s", help="the name or url of a required schema"),
|
|
1080
|
+
] = [],
|
|
1081
|
+
model: Annotated[
|
|
1082
|
+
str, typer.Option(..., help="Name of the LLM model to use for the task runner")
|
|
1083
|
+
] = "gpt-5.2",
|
|
1084
|
+
image_generation: Annotated[
|
|
1085
|
+
Optional[str], typer.Option(..., help="Name of an image gen model")
|
|
1086
|
+
] = None,
|
|
1087
|
+
local_shell: Annotated[
|
|
1088
|
+
Optional[bool], typer.Option(..., help="Enable local shell tool calling")
|
|
1089
|
+
] = False,
|
|
1090
|
+
shell: Annotated[
|
|
1091
|
+
Optional[bool], typer.Option(..., help="Enable function shell tool calling")
|
|
1092
|
+
] = False,
|
|
1093
|
+
apply_patch: Annotated[
|
|
1094
|
+
Optional[bool], typer.Option(..., help="Enable apply patch tool")
|
|
1095
|
+
] = False,
|
|
1096
|
+
web_search: Annotated[
|
|
1097
|
+
Optional[bool], typer.Option(..., help="Enable web search tool calling")
|
|
1098
|
+
] = False,
|
|
1099
|
+
mcp: Annotated[
|
|
1100
|
+
Optional[bool], typer.Option(..., help="Enable mcp tool calling")
|
|
1101
|
+
] = False,
|
|
1102
|
+
storage: Annotated[
|
|
1103
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit")
|
|
1104
|
+
] = False,
|
|
1105
|
+
require_image_generation: Annotated[
|
|
1106
|
+
Optional[str], typer.Option(..., help="Name of an image gen model", hidden=True)
|
|
1107
|
+
] = None,
|
|
1108
|
+
require_local_shell: Annotated[
|
|
1109
|
+
Optional[bool],
|
|
1110
|
+
typer.Option(..., help="Enable local shell tool calling", hidden=True),
|
|
1111
|
+
] = False,
|
|
1112
|
+
require_shell: Annotated[
|
|
1113
|
+
Optional[bool],
|
|
1114
|
+
typer.Option(..., help="Enable function shell tool calling", hidden=True),
|
|
1115
|
+
] = False,
|
|
1116
|
+
require_apply_patch: Annotated[
|
|
1117
|
+
Optional[bool], typer.Option(..., help="Enable apply patch tool", hidden=True)
|
|
1118
|
+
] = False,
|
|
1119
|
+
require_web_search: Annotated[
|
|
1120
|
+
Optional[bool],
|
|
1121
|
+
typer.Option(..., help="Enable web search tool calling", hidden=True),
|
|
1122
|
+
] = False,
|
|
1123
|
+
require_mcp: Annotated[
|
|
1124
|
+
Optional[bool], typer.Option(..., help="Enable mcp tool calling", hidden=True)
|
|
1125
|
+
] = False,
|
|
1126
|
+
require_storage: Annotated[
|
|
1127
|
+
Optional[bool], typer.Option(..., help="Enable storage toolkit", hidden=True)
|
|
1128
|
+
] = False,
|
|
1129
|
+
require_table_read: Annotated[
|
|
1130
|
+
list[str],
|
|
1131
|
+
typer.Option(
|
|
1132
|
+
..., help="Enable table read tools for a specific table", hidden=True
|
|
1133
|
+
),
|
|
1134
|
+
] = [],
|
|
1135
|
+
require_table_write: Annotated[
|
|
1136
|
+
list[str],
|
|
1137
|
+
typer.Option(
|
|
1138
|
+
..., help="Enable table write tools for a specific table", hidden=True
|
|
1139
|
+
),
|
|
1140
|
+
] = [],
|
|
1141
|
+
require_read_only_storage: Annotated[
|
|
1142
|
+
Optional[bool],
|
|
1143
|
+
typer.Option(..., help="Enable read only storage toolkit", hidden=True),
|
|
1144
|
+
] = False,
|
|
1145
|
+
working_directory: Annotated[
|
|
1146
|
+
Optional[str],
|
|
1147
|
+
typer.Option(..., help="The default working directory for shell commands"),
|
|
1148
|
+
] = None,
|
|
1149
|
+
delegate_shell_token: Annotated[
|
|
1150
|
+
Optional[bool],
|
|
1151
|
+
typer.Option(..., help="Delegate the room token to shell tools"),
|
|
1152
|
+
] = False,
|
|
1153
|
+
require_document_authoring: Annotated[
|
|
1154
|
+
Optional[bool],
|
|
1155
|
+
typer.Option(..., help="Enable document authoring", hidden=True),
|
|
1156
|
+
] = False,
|
|
1157
|
+
require_discovery: Annotated[
|
|
1158
|
+
Optional[bool],
|
|
1159
|
+
typer.Option(..., help="Enable discovery of agents and tools", hidden=True),
|
|
1160
|
+
] = False,
|
|
1161
|
+
llm_participant: Annotated[
|
|
1162
|
+
Optional[str],
|
|
1163
|
+
typer.Option(
|
|
1164
|
+
..., help="Delegate LLM interactions to a remote participant", hidden=True
|
|
1165
|
+
),
|
|
1166
|
+
] = None,
|
|
1167
|
+
host: Annotated[
|
|
1168
|
+
Optional[str], typer.Option(help="Host to bind the service on")
|
|
1169
|
+
] = None,
|
|
1170
|
+
port: Annotated[
|
|
1171
|
+
Optional[int], typer.Option(help="Port to bind the service on")
|
|
1172
|
+
] = None,
|
|
1173
|
+
path: Annotated[
|
|
1174
|
+
Optional[str], typer.Option(help="HTTP path to mount the service at")
|
|
1175
|
+
] = None,
|
|
1176
|
+
output_schema: Annotated[
|
|
1177
|
+
Optional[str],
|
|
1178
|
+
typer.Option(..., help="an output schema to use", hidden=True),
|
|
1179
|
+
] = None,
|
|
1180
|
+
output_schema_path: Annotated[
|
|
1181
|
+
Optional[str],
|
|
1182
|
+
typer.Option(..., help="the path or url to output schema to use", hidden=True),
|
|
1183
|
+
] = None,
|
|
1184
|
+
annotations: Annotated[
|
|
1185
|
+
str,
|
|
1186
|
+
typer.Option(
|
|
1187
|
+
"--annotations", "-a", help='annotations in json format {"name":"value"}'
|
|
1188
|
+
),
|
|
1189
|
+
] = '{"meshagent.task-runner.attachment-format":"tar"}',
|
|
1190
|
+
title: Annotated[
|
|
1191
|
+
Optional[str], typer.Option(..., help="a friendly name for the task runner")
|
|
1192
|
+
] = None,
|
|
1193
|
+
description: Annotated[
|
|
1194
|
+
Optional[str], typer.Option(..., help="a description for the task runner")
|
|
1195
|
+
] = None,
|
|
1196
|
+
project_id: ProjectIdOption,
|
|
1197
|
+
room: Annotated[
|
|
1198
|
+
Optional[str],
|
|
1199
|
+
typer.Option("--room", help="The name of a room to create the service for"),
|
|
1200
|
+
] = None,
|
|
1201
|
+
):
|
|
1202
|
+
project_id = await resolve_project_id(project_id=project_id)
|
|
1203
|
+
|
|
1204
|
+
service = get_service(host=host, port=port)
|
|
1205
|
+
if path is None:
|
|
1206
|
+
path = "/agent"
|
|
1207
|
+
i = 0
|
|
1208
|
+
while service.has_path(path):
|
|
1209
|
+
i += 1
|
|
1210
|
+
path = f"/agent{i}"
|
|
1211
|
+
|
|
1212
|
+
service.agents.append(
|
|
1213
|
+
AgentSpec(name=agent_name, annotations={ANNOTATION_AGENT_TYPE: "TaskRunner"})
|
|
1214
|
+
)
|
|
1215
|
+
|
|
1216
|
+
service.add_path(
|
|
1217
|
+
identity=agent_name,
|
|
1218
|
+
path=path,
|
|
1219
|
+
cls=build_task_runner(
|
|
1220
|
+
model=model,
|
|
1221
|
+
local_shell=local_shell,
|
|
1222
|
+
shell=shell,
|
|
1223
|
+
apply_patch=apply_patch,
|
|
1224
|
+
title=title,
|
|
1225
|
+
description=description,
|
|
1226
|
+
rule=rule,
|
|
1227
|
+
toolkit=toolkit,
|
|
1228
|
+
schema=schema,
|
|
1229
|
+
rules_file=rules_file,
|
|
1230
|
+
web_search=web_search,
|
|
1231
|
+
image_generation=image_generation,
|
|
1232
|
+
mcp=mcp,
|
|
1233
|
+
storage=storage,
|
|
1234
|
+
require_web_search=require_web_search,
|
|
1235
|
+
require_shell=require_shell,
|
|
1236
|
+
require_apply_patch=require_apply_patch,
|
|
1237
|
+
require_local_shell=require_local_shell,
|
|
1238
|
+
require_image_generation=require_image_generation,
|
|
1239
|
+
require_mcp=require_mcp,
|
|
1240
|
+
require_storage=require_storage,
|
|
1241
|
+
require_table_write=require_table_write,
|
|
1242
|
+
require_table_read=require_table_read,
|
|
1243
|
+
require_read_only_storage=require_read_only_storage,
|
|
1244
|
+
room_rules_path=room_rules,
|
|
1245
|
+
working_directory=working_directory,
|
|
1246
|
+
delegate_shell_token=delegate_shell_token,
|
|
1247
|
+
require_document_authoring=require_document_authoring,
|
|
1248
|
+
require_discovery=require_discovery,
|
|
1249
|
+
llm_participant=llm_participant,
|
|
1250
|
+
output_schema_str=output_schema,
|
|
1251
|
+
output_schema_path=output_schema_path,
|
|
1252
|
+
annotations=json.loads(annotations) if annotations != "" else {},
|
|
1253
|
+
),
|
|
1254
|
+
)
|
|
1255
|
+
|
|
1256
|
+
spec = service_specs()[0]
|
|
1257
|
+
spec.metadata.annotations = {
|
|
1258
|
+
"meshagent.service.id": service_name,
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
spec.metadata.name = service_name
|
|
1262
|
+
spec.metadata.description = service_description
|
|
1263
|
+
spec.container.image = (
|
|
1264
|
+
"us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz"
|
|
1265
|
+
)
|
|
1266
|
+
spec.container.command = shlex.join(
|
|
1267
|
+
["meshagent", "task-runner", "service", *cleanup_args(sys.argv[2:])]
|
|
1268
|
+
)
|
|
1269
|
+
|
|
1270
|
+
client = await get_client()
|
|
1271
|
+
try:
|
|
1272
|
+
id = None
|
|
1273
|
+
try:
|
|
1274
|
+
if id is None:
|
|
1275
|
+
if room is None:
|
|
1276
|
+
services = await client.list_services(project_id=project_id)
|
|
1277
|
+
else:
|
|
1278
|
+
services = await client.list_room_services(
|
|
1279
|
+
project_id=project_id, room_name=room
|
|
1280
|
+
)
|
|
1281
|
+
|
|
1282
|
+
for s in services:
|
|
1283
|
+
if s.metadata.name == spec.metadata.name:
|
|
1284
|
+
id = s.id
|
|
1285
|
+
|
|
1286
|
+
if id is None:
|
|
1287
|
+
if room is None:
|
|
1288
|
+
id = await client.create_service(
|
|
1289
|
+
project_id=project_id, service=spec
|
|
1290
|
+
)
|
|
1291
|
+
else:
|
|
1292
|
+
id = await client.create_room_service(
|
|
1293
|
+
project_id=project_id, service=spec, room_name=room
|
|
1294
|
+
)
|
|
1295
|
+
|
|
1296
|
+
else:
|
|
1297
|
+
spec.id = id
|
|
1298
|
+
if room is None:
|
|
1299
|
+
await client.update_service(
|
|
1300
|
+
project_id=project_id, service_id=id, service=spec
|
|
1301
|
+
)
|
|
1302
|
+
else:
|
|
1303
|
+
await client.update_room_service(
|
|
1304
|
+
project_id=project_id,
|
|
1305
|
+
service_id=id,
|
|
1306
|
+
service=spec,
|
|
1307
|
+
room_name=room,
|
|
1308
|
+
)
|
|
1309
|
+
|
|
1310
|
+
except ConflictError:
|
|
1311
|
+
print(f"[red]Service name already in use: {spec.metadata.name}[/red]")
|
|
1312
|
+
raise typer.Exit(code=1)
|
|
1313
|
+
else:
|
|
1314
|
+
print(f"[green]Deployed service:[/] {id}")
|
|
1315
|
+
|
|
1316
|
+
finally:
|
|
1317
|
+
await client.close()
|