meshagent-cli 0.7.0__py3-none-any.whl → 0.21.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. meshagent/cli/agent.py +15 -11
  2. meshagent/cli/api_keys.py +4 -4
  3. meshagent/cli/async_typer.py +52 -4
  4. meshagent/cli/call.py +12 -8
  5. meshagent/cli/chatbot.py +1007 -129
  6. meshagent/cli/cli.py +21 -20
  7. meshagent/cli/cli_mcp.py +92 -28
  8. meshagent/cli/cli_secrets.py +10 -10
  9. meshagent/cli/common_options.py +19 -4
  10. meshagent/cli/containers.py +164 -16
  11. meshagent/cli/database.py +997 -0
  12. meshagent/cli/developer.py +3 -3
  13. meshagent/cli/exec.py +22 -6
  14. meshagent/cli/helper.py +62 -11
  15. meshagent/cli/helpers.py +66 -9
  16. meshagent/cli/host.py +37 -0
  17. meshagent/cli/mailbot.py +1004 -40
  18. meshagent/cli/mailboxes.py +223 -0
  19. meshagent/cli/meeting_transcriber.py +10 -4
  20. meshagent/cli/messaging.py +7 -7
  21. meshagent/cli/multi.py +402 -0
  22. meshagent/cli/oauth2.py +44 -21
  23. meshagent/cli/participant_token.py +5 -3
  24. meshagent/cli/port.py +70 -0
  25. meshagent/cli/queue.py +2 -2
  26. meshagent/cli/room.py +20 -212
  27. meshagent/cli/rooms.py +214 -0
  28. meshagent/cli/services.py +32 -23
  29. meshagent/cli/sessions.py +5 -5
  30. meshagent/cli/storage.py +5 -5
  31. meshagent/cli/task_runner.py +770 -0
  32. meshagent/cli/version.py +1 -1
  33. meshagent/cli/voicebot.py +502 -76
  34. meshagent/cli/webhook.py +7 -7
  35. meshagent/cli/worker.py +1327 -0
  36. {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/METADATA +13 -13
  37. meshagent_cli-0.21.0.dist-info/RECORD +44 -0
  38. meshagent_cli-0.7.0.dist-info/RECORD +0 -36
  39. {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/WHEEL +0 -0
  40. {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/entry_points.txt +0 -0
  41. {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.21.0.dist-info}/top_level.txt +0 -0
meshagent/cli/agent.py CHANGED
@@ -15,16 +15,16 @@ from meshagent.cli.helper import resolve_project_id
15
15
  from meshagent.cli import async_typer
16
16
  from meshagent.cli.helper import get_client, resolve_room
17
17
 
18
- app = async_typer.AsyncTyper()
18
+ app = async_typer.AsyncTyper(help="Interact with agents and toolkits in a room")
19
19
 
20
20
 
21
- @app.async_command("ask")
21
+ @app.async_command("ask", help="Send a request to an agent")
22
22
  async def ask(
23
23
  *,
24
- project_id: ProjectIdOption = None,
24
+ project_id: ProjectIdOption,
25
25
  room: RoomOption,
26
- agent: Annotated[str, typer.Option()],
27
- input: Annotated[str, typer.Option()],
26
+ agent: Annotated[str, typer.Option(..., help="Agent name to ask")],
27
+ input: Annotated[str, typer.Option(..., help="JSON string with tool arguments")],
28
28
  timeout: Annotated[
29
29
  Optional[int],
30
30
  typer.Option(
@@ -32,6 +32,8 @@ async def ask(
32
32
  ),
33
33
  ] = 30,
34
34
  ):
35
+ """Wait for an agent to join, then send it an ask request."""
36
+
35
37
  account_client = await get_client()
36
38
  try:
37
39
  project_id = await resolve_project_id(project_id=project_id)
@@ -76,10 +78,10 @@ async def ask(
76
78
  await account_client.close()
77
79
 
78
80
 
79
- @app.async_command("invoke-tool")
81
+ @app.async_command("invoke-tool", help="Invoke a specific tool from a toolkit")
80
82
  async def invoke_tool(
81
83
  *,
82
- project_id: ProjectIdOption = None,
84
+ project_id: ProjectIdOption,
83
85
  room: RoomOption,
84
86
  toolkit: Annotated[str, typer.Option(..., help="Toolkit name")],
85
87
  tool: Annotated[str, typer.Option(..., help="Tool name")],
@@ -161,10 +163,10 @@ async def invoke_tool(
161
163
  await account_client.close()
162
164
 
163
165
 
164
- @app.async_command("list-agents")
166
+ @app.async_command("list-agents", help="List agents currently in the room")
165
167
  async def list_agents_command(
166
168
  *,
167
- project_id: ProjectIdOption = None,
169
+ project_id: ProjectIdOption,
168
170
  room: RoomOption,
169
171
  ):
170
172
  """
@@ -205,10 +207,12 @@ async def list_agents_command(
205
207
  await account_client.close()
206
208
 
207
209
 
208
- @app.async_command("list-toolkits")
210
+ @app.async_command(
211
+ "list-toolkits", help="List toolkits (and tools) available in the room"
212
+ )
209
213
  async def list_toolkits_command(
210
214
  *,
211
- project_id: ProjectIdOption = None,
215
+ project_id: ProjectIdOption,
212
216
  room: RoomOption,
213
217
  role: str = "user",
214
218
  participant_id: Annotated[
meshagent/cli/api_keys.py CHANGED
@@ -19,7 +19,7 @@ app = async_typer.AsyncTyper(help="Manage or activate api-keys for your project"
19
19
  @app.async_command("list")
20
20
  async def list(
21
21
  *,
22
- project_id: ProjectIdOption = None,
22
+ project_id: ProjectIdOption,
23
23
  o: OutputFormatOption = "table",
24
24
  ):
25
25
  project_id = await resolve_project_id(project_id=project_id)
@@ -42,7 +42,7 @@ async def list(
42
42
  @app.async_command("create")
43
43
  async def create(
44
44
  *,
45
- project_id: ProjectIdOption = None,
45
+ project_id: ProjectIdOption,
46
46
  name: str,
47
47
  description: Annotated[
48
48
  str, typer.Option(..., help="a description for the api key")
@@ -85,7 +85,7 @@ async def create(
85
85
  @app.async_command("activate")
86
86
  async def activate(
87
87
  *,
88
- project_id: ProjectIdOption = None,
88
+ project_id: ProjectIdOption,
89
89
  key: str,
90
90
  ):
91
91
  project_id = await resolve_project_id(project_id=project_id)
@@ -94,7 +94,7 @@ async def activate(
94
94
 
95
95
 
96
96
  @app.async_command("delete")
97
- async def delete(*, project_id: ProjectIdOption = None, id: str):
97
+ async def delete(*, project_id: ProjectIdOption, id: str):
98
98
  project_id = await resolve_project_id(project_id=project_id)
99
99
 
100
100
  client = await get_client()
@@ -2,20 +2,64 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import inspect
5
+ import threading
5
6
  from functools import partial, wraps
6
- from typing import Any, Callable
7
+ from typing import Any, Callable, TypeVar
7
8
 
8
9
  from typer import Typer
9
10
 
11
+ T = TypeVar("T")
12
+
13
+
14
+ def _run_coroutine_sync(
15
+ coro: "asyncio.Future[T] | asyncio.coroutines.Coroutine[Any, Any, T]",
16
+ ) -> T:
17
+ """
18
+ Run an awaitable from sync code.
19
+
20
+ - If we're not currently in an event loop, use asyncio.run().
21
+ - If we ARE in a running loop (e.g. inside an agent / notebook / ASGI app),
22
+ run asyncio.run() in a separate thread and block for the result.
23
+
24
+ This avoids: RuntimeError: asyncio.run() cannot be called from a running event loop
25
+ """
26
+ try:
27
+ asyncio.get_running_loop()
28
+ in_running_loop = True
29
+ except RuntimeError:
30
+ in_running_loop = False
31
+
32
+ if not in_running_loop:
33
+ return asyncio.run(coro) # type: ignore[arg-type]
34
+
35
+ result: dict[str, Any] = {}
36
+ done = threading.Event()
37
+
38
+ def _worker() -> None:
39
+ try:
40
+ result["value"] = asyncio.run(coro) # type: ignore[arg-type]
41
+ except BaseException as e:
42
+ result["error"] = e
43
+ finally:
44
+ done.set()
45
+
46
+ t = threading.Thread(target=_worker, daemon=True)
47
+ t.start()
48
+ done.wait()
49
+
50
+ if "error" in result:
51
+ raise result["error"]
52
+ return result["value"] # type: ignore[return-value]
53
+
10
54
 
11
55
  class AsyncTyper(Typer):
12
56
  @staticmethod
13
- def maybe_run_async(decorator: Callable, func: Callable) -> Any:
57
+ def maybe_run_async(decorator: Callable[..., Any], func: Callable[..., Any]) -> Any:
14
58
  if inspect.iscoroutinefunction(func):
15
59
 
16
60
  @wraps(func)
17
61
  def runner(*args: Any, **kwargs: Any) -> Any:
18
- return asyncio.run(func(*args, **kwargs))
62
+ return _run_coroutine_sync(func(*args, **kwargs))
19
63
 
20
64
  decorator(runner)
21
65
  else:
@@ -26,6 +70,10 @@ class AsyncTyper(Typer):
26
70
  decorator = super().callback(*args, **kwargs)
27
71
  return partial(self.maybe_run_async, decorator)
28
72
 
29
- def async_command(self, *args: Any, **kwargs: Any) -> Any:
73
+ def command(self, *args: Any, **kwargs: Any) -> Any:
30
74
  decorator = super().command(*args, **kwargs)
31
75
  return partial(self.maybe_run_async, decorator)
76
+
77
+ # keep your existing name if you prefer
78
+ def async_command(self, *args: Any, **kwargs: Any) -> Any:
79
+ return self.command(*args, **kwargs)
meshagent/cli/call.py CHANGED
@@ -24,7 +24,7 @@ import pathlib
24
24
  from pydantic_yaml import parse_yaml_raw_as
25
25
  from meshagent.api.participant_token import ParticipantTokenSpec
26
26
 
27
- app = async_typer.AsyncTyper()
27
+ app = async_typer.AsyncTyper(help="Trigger agent/tool calls via URL")
28
28
 
29
29
  PRIVATE_NETS = (
30
30
  ipaddress.ip_network("10.0.0.0/8"),
@@ -68,13 +68,13 @@ def is_local_url(url: str) -> bool:
68
68
  return True
69
69
 
70
70
 
71
- @app.async_command("schema")
72
- @app.async_command("toolkit")
73
- @app.async_command("agent")
74
- @app.async_command("tool")
71
+ @app.async_command("schema", help="Send a call request to a schema webhook URL")
72
+ @app.async_command("toolkit", help="Send a call request to a toolkit webhook URL")
73
+ @app.async_command("agent", help="Send a call request to an agent webhook URL")
74
+ @app.async_command("tool", help="Send a call request to a tool webhook URL")
75
75
  async def make_call(
76
76
  *,
77
- project_id: ProjectIdOption = None,
77
+ project_id: ProjectIdOption,
78
78
  room: RoomOption,
79
79
  role: str = "agent",
80
80
  local: Optional[bool] = None,
@@ -103,6 +103,8 @@ async def make_call(
103
103
  typer.Option("--key", help="an api key to sign the token with"),
104
104
  ] = None,
105
105
  ):
106
+ """Send a `room.call` request to a URL or in-room agent."""
107
+
106
108
  key = await resolve_key(project_id=project_id, key=key)
107
109
 
108
110
  if permissions is not None:
@@ -136,7 +138,7 @@ async def make_call(
136
138
 
137
139
  async def _make_call(
138
140
  *,
139
- project_id: ProjectIdOption = None,
141
+ project_id: ProjectIdOption,
140
142
  room: RoomOption,
141
143
  role: str = "agent",
142
144
  local: Optional[bool] = None,
@@ -198,7 +200,9 @@ async def _make_call(
198
200
  "room_url": websocket_room_url(room_name=room),
199
201
  "room_name": room,
200
202
  "token": token.to_jwt(api_key=key),
201
- "arguments": arguments,
203
+ "arguments": json.loads(arguments)
204
+ if isinstance(arguments, str)
205
+ else arguments,
202
206
  }
203
207
 
204
208
  await send_webhook(