meshagent-cli 0.5.18__py3-none-any.whl → 0.6.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.

Potentially problematic release.


This version of meshagent-cli might be problematic. Click here for more details.

meshagent/cli/mailbot.py CHANGED
@@ -1,36 +1,33 @@
1
- from meshagent.agents.mail import MailWorker
2
-
3
1
  import typer
4
2
  from meshagent.api import ParticipantToken
5
3
  from rich import print
6
4
  from typing import Annotated, Optional
7
5
  from meshagent.cli.common_options import (
8
6
  ProjectIdOption,
9
- ApiKeyIdOption,
10
7
  RoomOption,
11
8
  )
12
9
  from meshagent.tools import Toolkit
13
- from meshagent.api import RoomClient, WebSocketClientProtocol
10
+ from meshagent.api import RoomClient, WebSocketClientProtocol, ApiScope
14
11
  from meshagent.api.helpers import meshagent_base_url, websocket_room_url
15
12
  from meshagent.cli import async_typer
16
13
  from meshagent.cli.helper import (
17
14
  get_client,
18
15
  resolve_project_id,
19
- resolve_api_key,
20
- resolve_token_jwt,
21
16
  resolve_room,
17
+ resolve_key,
22
18
  )
23
19
  from meshagent.openai import OpenAIResponsesAdapter
24
20
  from meshagent.openai.tools.responses_adapter import ImageGenerationTool, LocalShellTool
25
21
  from meshagent.api.services import ServiceHost
26
22
 
27
- from meshagent.agents.mail import room_address
23
+
28
24
  from typing import List
29
25
  from pathlib import Path
30
26
 
31
27
  from meshagent.api import RequiredToolkit, RequiredSchema
32
28
  from meshagent.openai.tools.responses_adapter import WebSearchTool
33
29
 
30
+
34
31
  app = async_typer.AsyncTyper(help="Join a mailbot to a room")
35
32
 
36
33
 
@@ -48,7 +45,10 @@ def build_mailbot(
48
45
  web_search: Annotated[
49
46
  Optional[bool], typer.Option(..., help="Enable web search tool calling")
50
47
  ] = False,
48
+ queue: str,
51
49
  ):
50
+ from meshagent.agents.mail import MailWorker
51
+
52
52
  requirements = []
53
53
 
54
54
  toolkits = []
@@ -79,15 +79,13 @@ def build_mailbot(
79
79
  name=agent_name,
80
80
  requires=requirements,
81
81
  toolkits=toolkits,
82
+ queue=queue,
82
83
  rules=rule if len(rule) > 0 else None,
83
84
  )
84
85
 
85
86
  async def start(self, *, room: RoomClient):
86
- parsed_token = ParticipantToken.from_jwt(
87
- room.protocol.token, validate=False
88
- )
89
87
  print(
90
- f"[bold green]Send an email interact with your mailbot: {room_address(project_id=parsed_token.project_id, room_name=room.room_name)}[/bold green]"
88
+ "[bold green]Configure and send an email interact with your mailbot[/bold green]"
91
89
  )
92
90
  return await super().start(room=room)
93
91
 
@@ -124,11 +122,9 @@ def build_mailbot(
124
122
  async def make_call(
125
123
  *,
126
124
  project_id: ProjectIdOption = None,
127
- room: RoomOption = None,
128
- api_key_id: ApiKeyIdOption = None,
125
+ room: RoomOption,
129
126
  role: str = "agent",
130
127
  agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
131
- token_path: Annotated[Optional[str], typer.Option()] = None,
132
128
  rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
133
129
  rules_file: Optional[str] = None,
134
130
  toolkit: Annotated[
@@ -141,29 +137,38 @@ async def make_call(
141
137
  ] = [],
142
138
  model: Annotated[
143
139
  str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
144
- ] = "gpt-4o",
140
+ ] = "gpt-5",
145
141
  local_shell: Annotated[
146
142
  Optional[bool], typer.Option(..., help="Enable local shell tool calling")
147
143
  ] = False,
148
144
  web_search: Annotated[
149
145
  Optional[bool], typer.Option(..., help="Enable web search tool calling")
150
146
  ] = False,
147
+ key: Annotated[
148
+ str,
149
+ typer.Option("--key", help="an api key to sign the token with"),
150
+ ] = None,
151
+ queue: Annotated[str, typer.Option(..., help="the name of the mail queue")],
151
152
  ):
153
+ key = await resolve_key(project_id=project_id, key=key)
154
+
152
155
  account_client = await get_client()
153
156
  try:
154
157
  project_id = await resolve_project_id(project_id=project_id)
155
- api_key_id = await resolve_api_key(project_id, api_key_id)
156
158
 
157
159
  room = resolve_room(room)
158
- jwt = await resolve_token_jwt(
159
- project_id=project_id,
160
- api_key_id=api_key_id,
161
- token_path=token_path,
160
+
161
+ token = ParticipantToken(
162
162
  name=agent_name,
163
- role=role,
164
- room=room,
165
163
  )
166
164
 
165
+ token.add_api_grant(ApiScope.agent_default())
166
+
167
+ token.add_role_grant(role=role)
168
+ token.add_room_grant(room)
169
+
170
+ jwt = token.to_jwt(api_key=key)
171
+
167
172
  print("[bold green]Connecting to room...[/bold green]", flush=True)
168
173
  async with RoomClient(
169
174
  protocol=WebSocketClientProtocol(
@@ -190,6 +195,7 @@ async def make_call(
190
195
  image_generation=None,
191
196
  web_search=web_search,
192
197
  rules_file=rules_file,
198
+ queue=queue,
193
199
  )
194
200
 
195
201
  bot = CustomMailbot()
@@ -210,7 +216,6 @@ async def make_call(
210
216
  @app.async_command("service")
211
217
  async def service(
212
218
  *,
213
- room: RoomOption = None,
214
219
  agent_name: Annotated[str, typer.Option(..., help="Name of the agent to call")],
215
220
  rule: Annotated[List[str], typer.Option("--rule", "-r", help="a system rule")] = [],
216
221
  rules_file: Optional[str] = None,
@@ -224,22 +229,22 @@ async def service(
224
229
  ] = [],
225
230
  model: Annotated[
226
231
  str, typer.Option(..., help="Name of the LLM model to use for the chatbot")
227
- ] = "gpt-4o",
232
+ ] = "gpt-5",
228
233
  local_shell: Annotated[
229
234
  Optional[bool], typer.Option(..., help="Enable local shell tool calling")
230
235
  ] = False,
231
236
  host: Annotated[Optional[str], typer.Option()] = None,
232
237
  port: Annotated[Optional[int], typer.Option()] = None,
233
238
  path: Annotated[str, typer.Option()] = "/agent",
239
+ queue: Annotated[str, typer.Option(..., help="the name of the mail queue")],
234
240
  ):
235
- room = resolve_room(room)
236
-
237
241
  print("[bold green]Connecting to room...[/bold green]", flush=True)
238
242
 
239
243
  service = ServiceHost(host=host, port=port)
240
244
  service.add_path(
241
245
  path=path,
242
246
  cls=build_mailbot(
247
+ queue=queue,
243
248
  computer_use=None,
244
249
  model=model,
245
250
  local_shell=local_shell,
@@ -0,0 +1,124 @@
1
+ import typer
2
+ from rich import print
3
+ from typing import Annotated, Optional
4
+ from meshagent.cli.common_options import ProjectIdOption, RoomOption
5
+ from meshagent.api import RoomClient, WebSocketClientProtocol, RoomException
6
+ from meshagent.api.helpers import meshagent_base_url, websocket_room_url
7
+ from meshagent.cli import async_typer
8
+ from meshagent.api import ParticipantToken, ApiScope
9
+ from meshagent.cli.helper import (
10
+ get_client,
11
+ resolve_project_id,
12
+ resolve_room,
13
+ resolve_key,
14
+ )
15
+
16
+ from meshagent.api import RequiredSchema
17
+ from meshagent.api.services import ServiceHost
18
+
19
+ app = async_typer.AsyncTyper(help="Join a meeting transcriber to a room")
20
+
21
+
22
+ @app.async_command("join")
23
+ async def join(
24
+ *,
25
+ project_id: ProjectIdOption = None,
26
+ room: RoomOption,
27
+ agent_name: Annotated[str, typer.Option(..., help="Name of the agent")],
28
+ key: Annotated[
29
+ str,
30
+ typer.Option("--key", help="an api key to sign the token with"),
31
+ ] = None,
32
+ ):
33
+ try:
34
+ from meshagent.livekit.agents.meeting_transcriber import MeetingTranscriber
35
+ except ImportError:
36
+
37
+ class MeetingTranscriber:
38
+ def __init__(self, **kwargs):
39
+ raise RoomException(
40
+ "meshagent.livekit module not found, transcribers are not available"
41
+ )
42
+
43
+ key = await resolve_key(project_id=project_id, key=key)
44
+
45
+ account_client = await get_client()
46
+ try:
47
+ project_id = await resolve_project_id(project_id=project_id)
48
+ room = resolve_room(room)
49
+
50
+ token = ParticipantToken(
51
+ name=agent_name,
52
+ )
53
+
54
+ token.add_api_grant(ApiScope.agent_default())
55
+
56
+ token.add_role_grant(role="agent")
57
+ token.add_room_grant(room)
58
+
59
+ jwt = token.to_jwt(api_key=key)
60
+
61
+ print("[bold green]Connecting to room...[/bold green]", flush=True)
62
+ async with RoomClient(
63
+ protocol=WebSocketClientProtocol(
64
+ url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
65
+ token=jwt,
66
+ )
67
+ ) as client:
68
+ requirements = []
69
+
70
+ requirements.append(RequiredSchema(name="transcript"))
71
+
72
+ bot = MeetingTranscriber(
73
+ name=agent_name,
74
+ requires=requirements,
75
+ )
76
+
77
+ await bot.start(room=client)
78
+
79
+ try:
80
+ print(
81
+ f"[bold green]Open the studio to interact with your agent: {meshagent_base_url().replace('api.', 'studio.')}/projects/{project_id}/rooms/{client.room_name}[/bold green]",
82
+ flush=True,
83
+ )
84
+ await client.protocol.wait_for_close()
85
+ except KeyboardInterrupt:
86
+ await bot.stop()
87
+
88
+ finally:
89
+ await account_client.close()
90
+
91
+
92
+ @app.async_command("service")
93
+ async def service(
94
+ *,
95
+ agent_name: Annotated[str, typer.Option(..., help="Name of the agent")],
96
+ host: Annotated[Optional[str], typer.Option()] = None,
97
+ port: Annotated[Optional[int], typer.Option()] = None,
98
+ path: Annotated[str, typer.Option()] = "/agent",
99
+ ):
100
+ try:
101
+ from meshagent.livekit.agents.meeting_transcriber import MeetingTranscriber
102
+ except ImportError:
103
+
104
+ class MeetingTranscriber:
105
+ def __init__(self, **kwargs):
106
+ raise RoomException(
107
+ "meshagent.livekit module not found, voicebots are not available"
108
+ )
109
+
110
+ requirements = []
111
+
112
+ requirements.append(RequiredSchema(name="transcript"))
113
+
114
+ service = ServiceHost(host=host, port=port)
115
+
116
+ @service.path(path=path)
117
+ class CustomMeetingTranscriber(MeetingTranscriber):
118
+ def __init__(self):
119
+ super().__init__(
120
+ name=agent_name,
121
+ requires=requirements,
122
+ )
123
+
124
+ await service.run()
@@ -1,9 +1,8 @@
1
1
  import typer
2
2
  from rich import print
3
- from typing import Annotated, Optional
3
+ from typing import Annotated
4
4
  from meshagent.cli.common_options import (
5
5
  ProjectIdOption,
6
- ApiKeyIdOption,
7
6
  RoomOption,
8
7
  )
9
8
  import json
@@ -14,8 +13,6 @@ from meshagent.cli import async_typer
14
13
  from meshagent.cli.helper import (
15
14
  get_client,
16
15
  resolve_project_id,
17
- resolve_api_key,
18
- resolve_token_jwt,
19
16
  resolve_room,
20
17
  )
21
18
 
@@ -26,11 +23,7 @@ app = async_typer.AsyncTyper()
26
23
  async def messaging_list_participants_command(
27
24
  *,
28
25
  project_id: ProjectIdOption = None,
29
- room: RoomOption = None,
30
- token_path: Annotated[Optional[str], typer.Option()] = None,
31
- api_key_id: ApiKeyIdOption = None,
32
- name: Annotated[str, typer.Option()] = "cli",
33
- role: str = "user",
26
+ room: RoomOption,
34
27
  ):
35
28
  """
36
29
  List all messaging-enabled participants in the room.
@@ -39,24 +32,16 @@ async def messaging_list_participants_command(
39
32
  try:
40
33
  # Resolve project_id if not provided
41
34
  project_id = await resolve_project_id(project_id=project_id)
42
- api_key_id = await resolve_api_key(project_id, api_key_id)
43
35
 
44
36
  room = resolve_room(room)
45
37
 
46
- jwt = await resolve_token_jwt(
47
- project_id=project_id,
48
- api_key_id=api_key_id,
49
- token_path=token_path,
50
- name=name,
51
- role=role,
52
- room=room,
53
- )
38
+ connection = await account_client.connect_room(project_id=project_id, room=room)
54
39
 
55
40
  print("[bold green]Connecting to room...[/bold green]")
56
41
  async with RoomClient(
57
42
  protocol=WebSocketClientProtocol(
58
43
  url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
59
- token=jwt,
44
+ token=connection.jwt,
60
45
  )
61
46
  ) as client:
62
47
  # Must enable before we can see who else is enabled
@@ -80,14 +65,11 @@ async def messaging_list_participants_command(
80
65
  async def messaging_send_command(
81
66
  *,
82
67
  project_id: ProjectIdOption = None,
83
- room: RoomOption = None,
84
- token_path: Annotated[Optional[str], typer.Option()] = None,
85
- api_key_id: ApiKeyIdOption = None,
86
- name: Annotated[str, typer.Option()] = "cli",
87
- role: str = "user",
68
+ room: RoomOption,
88
69
  to_participant_id: Annotated[
89
70
  str, typer.Option(..., help="Participant ID to send a message to")
90
71
  ],
72
+ type: Annotated[str, typer.Option(..., help="type of the message to send")],
91
73
  data: Annotated[str, typer.Option(..., help="JSON message to send")],
92
74
  ):
93
75
  """
@@ -97,24 +79,15 @@ async def messaging_send_command(
97
79
  try:
98
80
  # Resolve project_id if not provided
99
81
  project_id = await resolve_project_id(project_id=project_id)
100
- api_key_id = await resolve_api_key(project_id, api_key_id)
101
-
102
82
  room = resolve_room(room)
103
83
 
104
- jwt = await resolve_token_jwt(
105
- project_id=project_id,
106
- api_key_id=api_key_id,
107
- token_path=token_path,
108
- name=name,
109
- role=role,
110
- room=room,
111
- )
84
+ connection = await account_client.connect_room(project_id=project_id, room=room)
112
85
 
113
86
  print("[bold green]Connecting to room...[/bold green]")
114
87
  async with RoomClient(
115
88
  protocol=WebSocketClientProtocol(
116
89
  url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
117
- token=jwt,
90
+ token=connection.jwt,
118
91
  )
119
92
  ) as client:
120
93
  # Create and enable messaging
@@ -136,7 +109,7 @@ async def messaging_send_command(
136
109
  # Send the message
137
110
  await client.messaging.send_message(
138
111
  to=participant,
139
- type="chat.message",
112
+ type=type,
140
113
  message=json.loads(data),
141
114
  attachment=None,
142
115
  )
@@ -151,11 +124,7 @@ async def messaging_send_command(
151
124
  async def messaging_broadcast_command(
152
125
  *,
153
126
  project_id: ProjectIdOption = None,
154
- room: RoomOption = None,
155
- token_path: Annotated[Optional[str], typer.Option()] = None,
156
- api_key_id: ApiKeyIdOption = None,
157
- name: Annotated[str, typer.Option()] = "cli",
158
- role: str = "user",
127
+ room: RoomOption,
159
128
  data: Annotated[str, typer.Option(..., help="JSON message to broadcast")],
160
129
  ):
161
130
  """
@@ -165,23 +134,15 @@ async def messaging_broadcast_command(
165
134
  try:
166
135
  # Resolve project_id if not provided
167
136
  project_id = await resolve_project_id(project_id=project_id)
168
- api_key_id = await resolve_api_key(project_id, api_key_id)
169
137
 
170
138
  room = resolve_room(room)
171
- jwt = await resolve_token_jwt(
172
- project_id=project_id,
173
- api_key_id=api_key_id,
174
- token_path=token_path,
175
- name=name,
176
- role=role,
177
- room=room,
178
- )
139
+ connection = await account_client.connect_room(project_id=project_id, room=room)
179
140
 
180
141
  print("[bold green]Connecting to room...[/bold green]")
181
142
  async with RoomClient(
182
143
  protocol=WebSocketClientProtocol(
183
144
  url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
184
- token=jwt,
145
+ token=connection.jwt,
185
146
  )
186
147
  ) as client:
187
148
  # Create and enable messaging
@@ -0,0 +1,189 @@
1
+ from meshagent.cli import async_typer
2
+ from meshagent.cli.common_options import ProjectIdOption, RoomOption
3
+ from meshagent.cli.helper import (
4
+ get_client,
5
+ resolve_project_id,
6
+ )
7
+ from meshagent.api.oauth import OAuthClientConfig
8
+ from meshagent.api import RoomClient, WebSocketClientProtocol
9
+ from meshagent.api.helpers import meshagent_base_url, websocket_room_url
10
+ from rich import print
11
+ from typing import Annotated, Optional
12
+ import typer
13
+ import json
14
+
15
+ app = async_typer.AsyncTyper(help="OAuth2 test commands")
16
+
17
+
18
+ @app.async_command("request")
19
+ async def oauth2(
20
+ *,
21
+ project_id: ProjectIdOption = None,
22
+ room: RoomOption,
23
+ from_participant_id: Annotated[str, typer.Option()],
24
+ client_id: Annotated[str, typer.Option()],
25
+ authorization_endpoint: Annotated[str, typer.Option()],
26
+ token_endpoint: Annotated[str, typer.Option()],
27
+ scopes: Annotated[Optional[str], typer.Option()] = None,
28
+ client_secret: Annotated[Optional[str], typer.Option()],
29
+ redirect_uri: Annotated[Optional[str], typer.Option()],
30
+ pkce: Annotated[bool, typer.Option()] = True,
31
+ ):
32
+ """
33
+ Run an OAuth2 request test between two participants in the same room.
34
+ One will act as the consumer, the other as the provider.
35
+ """
36
+
37
+ account_client = await get_client()
38
+ try:
39
+ project_id = await resolve_project_id(project_id=project_id)
40
+
41
+ jwt_consumer = await account_client.connect_room(
42
+ project_id=project_id, room=room
43
+ )
44
+
45
+ async with RoomClient(
46
+ protocol=WebSocketClientProtocol(
47
+ url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
48
+ token=jwt_consumer.jwt,
49
+ )
50
+ ) as consumer:
51
+ print("[green]Requesting OAuth token from consumer side...[/green]")
52
+ token = await consumer.secrets.request_oauth_token(
53
+ oauth=OAuthClientConfig(
54
+ client_id=client_id,
55
+ authorization_endpoint=authorization_endpoint,
56
+ token_endpoint=token_endpoint,
57
+ scopes=scopes.split(",") if scopes is not None else scopes,
58
+ client_secret=client_secret,
59
+ no_pkce=not pkce,
60
+ ),
61
+ from_participant_id=from_participant_id,
62
+ timeout=300,
63
+ redirect_uri=redirect_uri,
64
+ )
65
+
66
+ print(f"[bold cyan]Got access token:[/bold cyan] {token}")
67
+
68
+ finally:
69
+ await account_client.close()
70
+
71
+
72
+ @app.async_command("get")
73
+ async def get(
74
+ *,
75
+ project_id: ProjectIdOption = None,
76
+ room: RoomOption,
77
+ delegated_to: Annotated[str, typer.Option()],
78
+ client_id: Annotated[str, typer.Option()],
79
+ authorization_endpoint: Annotated[str, typer.Option()],
80
+ token_endpoint: Annotated[str, typer.Option()],
81
+ scopes: Annotated[Optional[str], typer.Option()] = None,
82
+ client_secret: Annotated[Optional[str], typer.Option()],
83
+ redirect_uri: Annotated[Optional[str], typer.Option()],
84
+ pkce: Annotated[bool, typer.Option()] = True,
85
+ ):
86
+ """
87
+ Run an OAuth2 request test between two participants in the same room.
88
+ One will act as the consumer, the other as the provider.
89
+ """
90
+
91
+ account_client = await get_client()
92
+ try:
93
+ project_id = await resolve_project_id(project_id=project_id)
94
+
95
+ jwt_consumer = await account_client.connect_room(
96
+ project_id=project_id, room=room
97
+ )
98
+
99
+ async with RoomClient(
100
+ protocol=WebSocketClientProtocol(
101
+ url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
102
+ token=jwt_consumer.jwt,
103
+ )
104
+ ) as consumer:
105
+ print("[green]Requesting OAuth token from consumer side...[/green]")
106
+ token = await consumer.secrets.get_offline_oauth_token(
107
+ oauth=OAuthClientConfig(
108
+ client_id=client_id,
109
+ authorization_endpoint=authorization_endpoint,
110
+ token_endpoint=token_endpoint,
111
+ scopes=scopes.split(",") if scopes is not None else scopes,
112
+ client_secret=client_secret,
113
+ no_pkce=not pkce,
114
+ ),
115
+ delegated_to=delegated_to,
116
+ )
117
+
118
+ print(f"[bold cyan]Got access token:[/bold cyan] {token}")
119
+
120
+ finally:
121
+ await account_client.close()
122
+
123
+
124
+ @app.async_command("list")
125
+ async def list(
126
+ *,
127
+ project_id: ProjectIdOption = None,
128
+ room: RoomOption,
129
+ ):
130
+ """
131
+ list secrets
132
+ """
133
+
134
+ account_client = await get_client()
135
+ try:
136
+ project_id = await resolve_project_id(project_id=project_id)
137
+
138
+ jwt_consumer = await account_client.connect_room(
139
+ project_id=project_id, room=room
140
+ )
141
+
142
+ async with RoomClient(
143
+ protocol=WebSocketClientProtocol(
144
+ url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
145
+ token=jwt_consumer.jwt,
146
+ )
147
+ ) as consumer:
148
+ secrets = await consumer.secrets.list_user_secrets()
149
+ output = []
150
+ for s in secrets:
151
+ output.append(s.model_dump(mode="json"))
152
+
153
+ print(json.dumps(output, indent=2))
154
+
155
+ finally:
156
+ await account_client.close()
157
+
158
+
159
+ @app.async_command("delete")
160
+ async def delete(
161
+ *,
162
+ project_id: ProjectIdOption = None,
163
+ room: RoomOption,
164
+ id: str,
165
+ delegated_to: Annotated[Optional[str], typer.Option()] = None,
166
+ ):
167
+ """
168
+ delete a secret
169
+ """
170
+
171
+ account_client = await get_client()
172
+ try:
173
+ project_id = await resolve_project_id(project_id=project_id)
174
+
175
+ jwt_consumer = await account_client.connect_room(
176
+ project_id=project_id, room=room
177
+ )
178
+
179
+ async with RoomClient(
180
+ protocol=WebSocketClientProtocol(
181
+ url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
182
+ token=jwt_consumer.jwt,
183
+ )
184
+ ) as consumer:
185
+ await consumer.secrets.delete_user_secret(id=id, delegated_to=delegated_to)
186
+ print("deleted secret")
187
+
188
+ finally:
189
+ await account_client.close()