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/agent.py +11 -62
- meshagent/cli/api_keys.py +46 -93
- meshagent/cli/auth_async.py +225 -68
- meshagent/cli/call.py +82 -19
- meshagent/cli/chatbot.py +83 -49
- meshagent/cli/cli.py +26 -70
- meshagent/cli/cli_mcp.py +61 -27
- meshagent/cli/cli_secrets.py +1 -1
- meshagent/cli/common_options.py +2 -10
- meshagent/cli/containers.py +577 -0
- meshagent/cli/developer.py +7 -25
- meshagent/cli/exec.py +162 -76
- meshagent/cli/helper.py +35 -67
- meshagent/cli/helpers.py +131 -0
- meshagent/cli/mailbot.py +31 -26
- meshagent/cli/meeting_transcriber.py +124 -0
- meshagent/cli/messaging.py +12 -51
- meshagent/cli/oauth2.py +189 -0
- meshagent/cli/participant_token.py +32 -21
- meshagent/cli/queue.py +6 -37
- meshagent/cli/services.py +300 -335
- meshagent/cli/storage.py +24 -89
- meshagent/cli/version.py +1 -1
- meshagent/cli/voicebot.py +39 -28
- meshagent/cli/webhook.py +3 -3
- {meshagent_cli-0.5.18.dist-info → meshagent_cli-0.6.0.dist-info}/METADATA +17 -11
- meshagent_cli-0.6.0.dist-info/RECORD +35 -0
- meshagent/cli/otel.py +0 -122
- meshagent_cli-0.5.18.dist-info/RECORD +0 -32
- {meshagent_cli-0.5.18.dist-info → meshagent_cli-0.6.0.dist-info}/WHEEL +0 -0
- {meshagent_cli-0.5.18.dist-info → meshagent_cli-0.6.0.dist-info}/entry_points.txt +0 -0
- {meshagent_cli-0.5.18.dist-info → meshagent_cli-0.6.0.dist-info}/top_level.txt +0 -0
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
|
-
|
|
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
|
-
|
|
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
|
|
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-
|
|
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
|
-
|
|
159
|
-
|
|
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-
|
|
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()
|
meshagent/cli/messaging.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import typer
|
|
2
2
|
from rich import print
|
|
3
|
-
from typing import Annotated
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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=
|
|
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
|
|
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
|
-
|
|
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
|
meshagent/cli/oauth2.py
ADDED
|
@@ -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()
|