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
@@ -14,13 +14,13 @@ from meshagent.api import (
14
14
  )
15
15
  from meshagent.api.helpers import meshagent_base_url, websocket_room_url
16
16
 
17
- app = async_typer.AsyncTyper()
17
+ app = async_typer.AsyncTyper(help="Developer utilities for a room")
18
18
 
19
19
 
20
- @app.async_command("watch")
20
+ @app.async_command("watch", help="Stream developer logs from a room")
21
21
  async def watch_logs(
22
22
  *,
23
- project_id: ProjectIdOption = None,
23
+ project_id: ProjectIdOption,
24
24
  room: RoomOption,
25
25
  ):
26
26
  """
meshagent/cli/exec.py CHANGED
@@ -82,13 +82,29 @@ def register(app: typer.Typer):
82
82
  @app.async_command("exec")
83
83
  async def exec_command(
84
84
  *,
85
- project_id: ProjectIdOption = None,
85
+ project_id: ProjectIdOption,
86
86
  room: RoomOption,
87
- name: Annotated[Optional[str], typer.Option()] = None,
88
- image: Annotated[Optional[str], typer.Option()] = None,
89
- command: Annotated[list[str], typer.Argument(...)] = None,
90
- tty: bool = False,
91
- room_storage_path: str = "/data",
87
+ name: Annotated[
88
+ Optional[str], typer.Option(help="Optional exec session name")
89
+ ] = None,
90
+ image: Annotated[
91
+ Optional[str],
92
+ typer.Option(help="Optional container image to use for the exec session"),
93
+ ] = None,
94
+ command: Annotated[
95
+ list[str],
96
+ typer.Argument(..., help="Command to execute (omit when using `--tty`)"),
97
+ ] = None,
98
+ tty: Annotated[
99
+ bool,
100
+ typer.Option(
101
+ "--tty/--no-tty",
102
+ help="Allocate an interactive TTY (requires a real terminal)",
103
+ ),
104
+ ] = False,
105
+ room_storage_path: Annotated[
106
+ str, typer.Option(help="Room storage mount path (default: /data)")
107
+ ] = "/data",
92
108
  ):
93
109
  """Open an interactive websocket‑based TTY."""
94
110
  client = await get_client()
meshagent/cli/helper.py CHANGED
@@ -7,7 +7,7 @@ from typing import Optional
7
7
  from meshagent.cli import auth_async
8
8
  from meshagent.cli import async_typer
9
9
  from meshagent.api.helpers import meshagent_base_url
10
- from meshagent.api.client import Meshagent
10
+ from meshagent.api.client import Meshagent, RoomConnectionInfo
11
11
  import os
12
12
  from rich import print
13
13
 
@@ -29,11 +29,15 @@ def _save_settings(s: Settings):
29
29
 
30
30
 
31
31
  def _load_settings():
32
- _ensure_cache_dir()
33
- if SETTINGS_FILE.exists():
34
- return Settings.model_validate_json(SETTINGS_FILE.read_text())
35
-
36
- return Settings()
32
+ try:
33
+ _ensure_cache_dir()
34
+ if SETTINGS_FILE.exists():
35
+ return Settings.model_validate_json(SETTINGS_FILE.read_text())
36
+ except OSError as ex:
37
+ if ex.errno == 30:
38
+ return Settings()
39
+ else:
40
+ raise
37
41
 
38
42
 
39
43
  async def get_active_project():
@@ -68,16 +72,33 @@ async def get_active_api_key(project_id: str):
68
72
  app = async_typer.AsyncTyper()
69
73
 
70
74
 
75
+ class CustomMeshagentClient(Meshagent):
76
+ async def connect_room(self, *, project_id: str, room: str) -> RoomConnectionInfo:
77
+ from urllib.parse import quote
78
+
79
+ jwt = os.getenv("MESHAGENT_SESSION_TOKEN")
80
+
81
+ if jwt is not None and room == os.getenv("MESHAGENT_ROOM"):
82
+ return RoomConnectionInfo(
83
+ jwt=jwt,
84
+ room_name=room,
85
+ project_id=os.getenv("MESHAGENT_PROJECT_ID"),
86
+ room_url=meshagent_base_url() + f"/rooms/{quote(room)}",
87
+ )
88
+
89
+ return await super().connect_room(project_id=project_id, room=room)
90
+
91
+
71
92
  async def get_client():
72
93
  key = os.getenv("MESHAGENT_API_KEY")
73
- if key is not None:
74
- return Meshagent(
94
+ if key is not None or os.getenv("MESHAGENT_SESSION_ID") is not None:
95
+ return CustomMeshagentClient(
75
96
  base_url=meshagent_base_url(),
76
97
  token=key,
77
98
  )
78
99
  else:
79
100
  access_token = await auth_async.get_access_token()
80
- return Meshagent(
101
+ return CustomMeshagentClient(
81
102
  base_url=meshagent_base_url(),
82
103
  token=access_token,
83
104
  )
@@ -119,7 +140,7 @@ def resolve_room(room_name: Optional[str] = None):
119
140
 
120
141
  async def resolve_project_id(project_id: Optional[str] = None):
121
142
  if project_id is None:
122
- project_id = await get_active_project()
143
+ project_id = os.getenv("MESHAGENT_PROJECT_ID") or await get_active_project()
123
144
 
124
145
  if project_id is None:
125
146
  print(
@@ -140,8 +161,38 @@ async def resolve_key(project_id: str | None, key: str | None):
140
161
 
141
162
  if key is None:
142
163
  print(
143
- "[red]--key is required if MESHGENT_API_KEY is not set. You can use meshagent api-key create to create a new api key."
164
+ "[red]--key is required if MESHAGENT_API_KEY is not set. You can use meshagent api-key create to create a new api key."
144
165
  )
145
166
  raise typer.Exit(1)
146
167
 
147
168
  return key
169
+
170
+
171
+ def cleanup_args(args: list[str]):
172
+ out = []
173
+ i = 0
174
+ while i < len(args):
175
+ if args[i] == "--service-name":
176
+ i += 1
177
+ elif args[i] == "--service-title":
178
+ i += 1
179
+ elif args[i] == "--service-description":
180
+ i += 1
181
+ elif args[i] == "--project-id":
182
+ i += 1
183
+ elif args[i] == "--room":
184
+ i += 1
185
+ elif args[i].startswith("--service-name="):
186
+ pass
187
+ elif args[i].startswith("--service-title="):
188
+ pass
189
+ elif args[i].startswith("--service-description="):
190
+ pass
191
+ elif args[i].startswith("--project-id="):
192
+ pass
193
+ elif args[i].startswith("--room="):
194
+ pass
195
+ else:
196
+ out.append(args[i])
197
+ i += 1
198
+ return out
meshagent/cli/helpers.py CHANGED
@@ -1,19 +1,20 @@
1
1
  from meshagent.cli import async_typer
2
2
 
3
-
4
3
  from meshagent.api import SchemaRegistry, SchemaRegistration
5
4
 
6
5
 
7
6
  import logging
8
7
 
9
- app = async_typer.AsyncTyper(help="Join a mailbot to a room")
8
+ app = async_typer.AsyncTyper(help="Developer helper services")
10
9
 
11
10
 
12
- @app.async_command("service")
11
+ @app.async_command("service", help="Run local helper HTTP services")
13
12
  async def helpers_service():
14
- from meshagent.agents.planning import DynamicPlanningResponder, PlanningResponder
13
+ """Run local helper services (agents, schemas, toolkits)."""
14
+ from meshagent.agents.llmrunner import LLMTaskRunner, DynamicLLMTaskRunner
15
15
  from meshagent.openai.tools import OpenAIResponsesAdapter
16
16
  from meshagent.tools.storage import StorageToolkit
17
+ from meshagent.tools.database import DatabaseToolkitBuilder
17
18
  from meshagent.api.services import ServiceHost
18
19
 
19
20
  from meshagent.agents.schemas.gallery import gallery_schema
@@ -24,20 +25,53 @@ async def helpers_service():
24
25
  )
25
26
  from meshagent.agents.schemas.presentation import presentation_schema
26
27
  from meshagent.agents import thread_schema
28
+ from meshagent.agents.widget_schema import widget_schema
27
29
 
28
30
  logging.getLogger("openai").setLevel(logging.ERROR)
29
31
  logging.getLogger("httpx").setLevel(logging.ERROR)
30
32
 
31
33
  service = ServiceHost(port=9000)
32
34
 
35
+ @service.path("/runner")
36
+ class Runner(LLMTaskRunner):
37
+ def __init__(self, **kwargs):
38
+ super().__init__(
39
+ name="meshagent.runner",
40
+ title="Generic Task Runner",
41
+ description="an agent that will perform a task with the selected tools",
42
+ llm_adapter=OpenAIResponsesAdapter(model="gpt-5.2"),
43
+ supports_tools=True,
44
+ input_prompt=True,
45
+ output_schema={
46
+ "type": "object",
47
+ "required": ["result"],
48
+ "additionalProperties": False,
49
+ "properties": {"result": {"type": "string"}},
50
+ },
51
+ annotations={"meshagent.task-runner.attachment-format": "tar"},
52
+ )
53
+
54
+ def get_toolkit_builders(self):
55
+ from meshagent.tools.storage import StorageToolkitBuilder
56
+ from meshagent.openai.tools.responses_adapter import WebSearchToolkitBuilder
57
+
58
+ providers = [
59
+ WebSearchToolkitBuilder(),
60
+ StorageToolkitBuilder(),
61
+ DatabaseToolkitBuilder(),
62
+ *super().get_toolkit_builders(),
63
+ ]
64
+
65
+ return providers
66
+
33
67
  @service.path("/planner")
34
- class Planner(PlanningResponder):
68
+ class Planner(LLMTaskRunner):
35
69
  def __init__(self, **kwargs):
36
70
  super().__init__(
37
71
  name="meshagent.planner",
38
- title="Generic Task Runner",
72
+ title="Generic Task Runner (Legacy)",
39
73
  description="an agent that will perform a task with the selected tools",
40
- llm_adapter=OpenAIResponsesAdapter(model="gpt-4.1"),
74
+ llm_adapter=OpenAIResponsesAdapter(model="gpt-5.2"),
41
75
  supports_tools=True,
42
76
  input_prompt=True,
43
77
  output_schema={
@@ -49,15 +83,27 @@ async def helpers_service():
49
83
  )
50
84
 
51
85
  @service.path("/schema_planner")
52
- class DynamicPlanner(DynamicPlanningResponder):
86
+ class DynamicPlanner(DynamicLLMTaskRunner):
53
87
  def __init__(self, **kwargs):
54
88
  super().__init__(
55
89
  name="meshagent.schema_planner",
56
90
  title="Schema Task Runner",
57
91
  description="an agent that can produces output that matches a schema",
58
- llm_adapter=OpenAIResponsesAdapter(model="gpt-4.1"),
92
+ llm_adapter=OpenAIResponsesAdapter(model="gpt-5.2"),
59
93
  )
60
94
 
95
+ def get_toolkit_builders(self):
96
+ from meshagent.tools.storage import StorageToolkitBuilder
97
+ from meshagent.openai.tools.responses_adapter import WebSearchToolkitBuilder
98
+
99
+ providers = [
100
+ WebSearchToolkitBuilder(),
101
+ StorageToolkitBuilder(),
102
+ *super().get_toolkit_builders(),
103
+ ]
104
+
105
+ return providers
106
+
61
107
  @service.path("/schemas/document")
62
108
  class DocumentSchemaRegistry(SchemaRegistry):
63
109
  def __init__(self):
@@ -102,6 +148,17 @@ async def helpers_service():
102
148
  schemas=[SchemaRegistration(name=name, schema=schema)],
103
149
  )
104
150
 
151
+ @service.path("/schemas/widget")
152
+ class WidgetDocumentSchemaRegistry(SchemaRegistry):
153
+ def __init__(self):
154
+ name = "widget"
155
+ schema = widget_schema
156
+ super().__init__(
157
+ name=f"meshagent.schema.{name}",
158
+ validate_webhook_secret=False,
159
+ schemas=[SchemaRegistration(name=name, schema=schema)],
160
+ )
161
+
105
162
  @service.path("/schemas/presentation")
106
163
  class PresentationDocumentSchemaRegistry(SchemaRegistry):
107
164
  def __init__(presentation):
meshagent/cli/host.py ADDED
@@ -0,0 +1,37 @@
1
+ from meshagent.api.services import ServiceHost
2
+ from meshagent.api.specs.service import ServiceSpec
3
+ import asyncio
4
+
5
+
6
+ options = {"deferred": False}
7
+ services = {}
8
+
9
+
10
+ def set_deferred(deferred: bool):
11
+ options["deferred"] = deferred
12
+
13
+
14
+ def get_deferred() -> bool:
15
+ return options["deferred"]
16
+
17
+
18
+ def get_service(port: int, host: str) -> ServiceHost:
19
+ if port not in services:
20
+ services[port] = ServiceHost(host=host, port=port)
21
+
22
+ return services[port]
23
+
24
+
25
+ def service_specs() -> list[ServiceSpec]:
26
+ specs = []
27
+ for port, s in services.items():
28
+ specs.append(s.get_service_spec(image=""))
29
+ return specs
30
+
31
+
32
+ async def run_services():
33
+ tasks = []
34
+ for port, s in services.items():
35
+ tasks.append(s.run())
36
+
37
+ await asyncio.gather(*tasks)