meshagent-cli 0.33.2__tar.gz → 0.34.0__tar.gz

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 (77) hide show
  1. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/PKG-INFO +13 -13
  2. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/queue.py +58 -9
  3. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/queue_test.py +112 -0
  4. meshagent_cli-0.34.0/meshagent/cli/version.py +1 -0
  5. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/webserver.py +9 -3
  6. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/webserver_test.py +123 -0
  7. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent_cli.egg-info/PKG-INFO +13 -13
  8. meshagent_cli-0.34.0/meshagent_cli.egg-info/requires.txt +29 -0
  9. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/pyproject.toml +12 -12
  10. meshagent_cli-0.33.2/meshagent/cli/version.py +0 -1
  11. meshagent_cli-0.33.2/meshagent_cli.egg-info/requires.txt +0 -29
  12. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/README.md +0 -0
  13. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/__init__.py +0 -0
  14. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/agent.py +0 -0
  15. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/api_keys.py +0 -0
  16. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/async_typer.py +0 -0
  17. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/auth.py +0 -0
  18. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/auth_async.py +0 -0
  19. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/call.py +0 -0
  20. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/chatbot.py +0 -0
  21. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/cli.py +0 -0
  22. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/cli_mcp.py +0 -0
  23. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/cli_secrets.py +0 -0
  24. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/cli_test.py +0 -0
  25. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/codex.py +0 -0
  26. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/common_options.py +0 -0
  27. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/containers.py +0 -0
  28. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/containers_test.py +0 -0
  29. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/database.py +0 -0
  30. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/developer.py +0 -0
  31. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/developer_test.py +0 -0
  32. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/helper.py +0 -0
  33. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/helper_test.py +0 -0
  34. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/helpers.py +0 -0
  35. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/host.py +0 -0
  36. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/mailbot.py +0 -0
  37. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/mailboxes.py +0 -0
  38. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/meeting_transcriber.py +0 -0
  39. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/memory.py +0 -0
  40. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/memory_test.py +0 -0
  41. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/messaging.py +0 -0
  42. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/multi.py +0 -0
  43. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/oauth2.py +0 -0
  44. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/participant_token.py +0 -0
  45. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/port.py +0 -0
  46. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/port_test.py +0 -0
  47. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/process.py +0 -0
  48. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/process_test.py +0 -0
  49. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/projects.py +0 -0
  50. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/room.py +0 -0
  51. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/room_services.py +0 -0
  52. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/rooms.py +0 -0
  53. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/routes.py +0 -0
  54. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/scheduled_tasks.py +0 -0
  55. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/scheduled_tasks_test.py +0 -0
  56. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/services.py +0 -0
  57. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/services_test.py +0 -0
  58. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/sessions.py +0 -0
  59. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/sessions_test.py +0 -0
  60. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/storage.py +0 -0
  61. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/storage_test.py +0 -0
  62. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/sync.py +0 -0
  63. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/sync_test.py +0 -0
  64. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/task_runner.py +0 -0
  65. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/test.py +0 -0
  66. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/tui/__init__.py +0 -0
  67. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/tui/setup.py +0 -0
  68. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/tui/setup_splash_frames.py +0 -0
  69. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/tui/setup_test.py +0 -0
  70. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/voicebot.py +0 -0
  71. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/webhook.py +0 -0
  72. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent/cli/worker.py +0 -0
  73. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent_cli.egg-info/SOURCES.txt +0 -0
  74. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent_cli.egg-info/dependency_links.txt +0 -0
  75. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent_cli.egg-info/entry_points.txt +0 -0
  76. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/meshagent_cli.egg-info/top_level.txt +0 -0
  77. {meshagent_cli-0.33.2 → meshagent_cli-0.34.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-cli
3
- Version: 0.33.2
3
+ Version: 0.34.0
4
4
  Summary: CLI for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -19,21 +19,21 @@ Requires-Dist: rich~=14.3.0
19
19
  Requires-Dist: textual<2.0,>=0.50
20
20
  Requires-Dist: prompt-toolkit~=3.0.52
21
21
  Provides-Extra: all
22
- Requires-Dist: meshagent-agents[all]~=0.33.2; extra == "all"
23
- Requires-Dist: meshagent-api[all]~=0.33.2; extra == "all"
24
- Requires-Dist: meshagent-computers~=0.33.2; extra == "all"
25
- Requires-Dist: meshagent-openai~=0.33.2; extra == "all"
26
- Requires-Dist: meshagent-anthropic~=0.33.2; extra == "all"
27
- Requires-Dist: meshagent-codex~=0.33.2; extra == "all"
28
- Requires-Dist: meshagent-mcp~=0.33.2; extra == "all"
29
- Requires-Dist: meshagent-tools~=0.33.2; extra == "all"
22
+ Requires-Dist: meshagent-agents[all]~=0.34.0; extra == "all"
23
+ Requires-Dist: meshagent-api[all]~=0.34.0; extra == "all"
24
+ Requires-Dist: meshagent-computers~=0.34.0; extra == "all"
25
+ Requires-Dist: meshagent-openai~=0.34.0; extra == "all"
26
+ Requires-Dist: meshagent-anthropic~=0.34.0; extra == "all"
27
+ Requires-Dist: meshagent-codex~=0.34.0; extra == "all"
28
+ Requires-Dist: meshagent-mcp~=0.34.0; extra == "all"
29
+ Requires-Dist: meshagent-tools~=0.34.0; extra == "all"
30
30
  Requires-Dist: supabase-auth~=2.28.0; extra == "all"
31
31
  Requires-Dist: prompt-toolkit~=3.0.52; extra == "all"
32
32
  Provides-Extra: mcp-service
33
- Requires-Dist: meshagent-agents[all]~=0.33.2; extra == "mcp-service"
34
- Requires-Dist: meshagent-api~=0.33.2; extra == "mcp-service"
35
- Requires-Dist: meshagent-mcp~=0.33.2; extra == "mcp-service"
36
- Requires-Dist: meshagent-tools~=0.33.2; extra == "mcp-service"
33
+ Requires-Dist: meshagent-agents[all]~=0.34.0; extra == "mcp-service"
34
+ Requires-Dist: meshagent-api~=0.34.0; extra == "mcp-service"
35
+ Requires-Dist: meshagent-mcp~=0.34.0; extra == "mcp-service"
36
+ Requires-Dist: meshagent-tools~=0.34.0; extra == "mcp-service"
37
37
  Requires-Dist: supabase-auth~=2.28.0; extra == "mcp-service"
38
38
 
39
39
  # [Meshagent](https://www.meshagent.com)
@@ -1,26 +1,75 @@
1
- import typer
2
- from rich import print
3
- from typing import Annotated, Optional
4
- from meshagent.cli.common_options import ProjectIdOption, RoomOption
5
- import json as _json
6
1
  import base64
2
+ import json as _json
7
3
  import mimetypes
8
4
  from pathlib import Path
5
+ from typing import Annotated, Optional
6
+
7
+ import typer
8
+ from rich import print
9
9
 
10
- from meshagent.api.helpers import websocket_room_url
11
10
  from meshagent.api import (
12
11
  RoomClient,
13
- WebSocketClientProtocol,
14
12
  RoomException,
13
+ WebSocketClientProtocol,
15
14
  )
15
+ from meshagent.api.helpers import websocket_room_url
16
+ from meshagent.api.room_server_client import Queue as RoomQueue
16
17
  from meshagent.agents.mail_common import create_email_message
17
- from meshagent.cli.helper import resolve_project_id, resolve_room
18
18
  from meshagent.cli import async_typer
19
- from meshagent.cli.helper import get_client
19
+ from meshagent.cli.common_options import OutputFormatOption, ProjectIdOption, RoomOption
20
+ from meshagent.cli.helper import (
21
+ get_client,
22
+ print_json_table,
23
+ resolve_project_id,
24
+ resolve_room,
25
+ )
20
26
 
21
27
  app = async_typer.AsyncTyper(help="Use queues in a room")
22
28
 
23
29
 
30
+ def _queue_rows(queues: list[RoomQueue]) -> list[dict[str, str | int]]:
31
+ return [{"name": item.name, "size": item.size} for item in queues]
32
+
33
+
34
+ @app.async_command("list", help="List queues in a room.")
35
+ async def queue_list(
36
+ *,
37
+ project_id: ProjectIdOption,
38
+ room: RoomOption,
39
+ output: OutputFormatOption = "table",
40
+ ):
41
+ account_client = await get_client()
42
+ try:
43
+ project_id = await resolve_project_id(project_id=project_id)
44
+ room = resolve_room(room)
45
+
46
+ connection = await account_client.connect_room(project_id=project_id, room=room)
47
+
48
+ async with RoomClient(
49
+ protocol=WebSocketClientProtocol(
50
+ url=websocket_room_url(room_name=room),
51
+ token=connection.jwt,
52
+ )
53
+ ) as client:
54
+ rows = _queue_rows(await client.queues.list())
55
+
56
+ if output == "json":
57
+ print(_json.dumps({"queues": rows}, indent=2))
58
+ return
59
+
60
+ if len(rows) == 0:
61
+ print("There are no queues currently in the room")
62
+ return
63
+
64
+ print_json_table(rows, "name", "size")
65
+
66
+ except RoomException as e:
67
+ print(e)
68
+ raise typer.Exit(1)
69
+ finally:
70
+ await account_client.close()
71
+
72
+
24
73
  @app.async_command("send", help="Send a JSON message to a room queue.")
25
74
  async def send(
26
75
  *,
@@ -150,6 +150,50 @@ async def _run_size(
150
150
  return account_client, printed
151
151
 
152
152
 
153
+ async def _run_queue_list(
154
+ *,
155
+ monkeypatch: pytest.MonkeyPatch,
156
+ room_name: str,
157
+ queues: list[_FakeQueue],
158
+ output: str = "table",
159
+ ) -> tuple[_FakeAccountClient, list[str], list[dict[str, object]]]:
160
+ account_client = _FakeAccountClient()
161
+ printed: list[str] = []
162
+ table_calls: list[dict[str, object]] = []
163
+
164
+ async def _fake_get_client() -> _FakeAccountClient:
165
+ return account_client
166
+
167
+ async def _fake_resolve_project_id(*, project_id):
168
+ del project_id
169
+ return "project-1"
170
+
171
+ def _fake_resolve_room(room: str) -> str:
172
+ return room
173
+
174
+ def _fake_print(*args, **kwargs) -> None:
175
+ del kwargs
176
+ printed.append(" ".join(str(arg) for arg in args))
177
+
178
+ def _fake_print_json_table(records: list[dict[str, object]], *cols: str) -> None:
179
+ table_calls.append({"records": records, "cols": cols})
180
+
181
+ monkeypatch.setattr(queue, "get_client", _fake_get_client)
182
+ monkeypatch.setattr(queue, "resolve_project_id", _fake_resolve_project_id)
183
+ monkeypatch.setattr(queue, "resolve_room", _fake_resolve_room)
184
+ monkeypatch.setattr(queue, "print_json_table", _fake_print_json_table)
185
+ _FakeRoomClient.default_queues = queues
186
+ monkeypatch.setattr(queue, "RoomClient", _FakeRoomClient)
187
+ monkeypatch.setattr(queue, "print", _fake_print)
188
+
189
+ await queue.queue_list(
190
+ project_id=None,
191
+ room=room_name,
192
+ output=output,
193
+ )
194
+ return account_client, printed, table_calls
195
+
196
+
153
197
  @pytest.mark.asyncio
154
198
  async def test_send_mail_queues_base64_email_payload(
155
199
  monkeypatch: pytest.MonkeyPatch,
@@ -242,6 +286,74 @@ async def test_send_mail_allows_empty_body(
242
286
  assert list(email_message.iter_attachments()) == []
243
287
 
244
288
 
289
+ @pytest.mark.asyncio
290
+ async def test_queue_list_prints_queue_rows(
291
+ monkeypatch: pytest.MonkeyPatch,
292
+ ) -> None:
293
+ account_client, printed, table_calls = await _run_queue_list(
294
+ monkeypatch=monkeypatch,
295
+ room_name="demo-room",
296
+ queues=[
297
+ _FakeQueue(name="jobs", size=3),
298
+ _FakeQueue(name="other", size=1),
299
+ ],
300
+ )
301
+
302
+ assert account_client.connect_calls == [
303
+ {"project_id": "project-1", "room": "demo-room"}
304
+ ]
305
+ assert account_client.closed is True
306
+ assert printed == []
307
+ assert table_calls == [
308
+ {
309
+ "records": [
310
+ {"name": "jobs", "size": 3},
311
+ {"name": "other", "size": 1},
312
+ ],
313
+ "cols": ("name", "size"),
314
+ }
315
+ ]
316
+
317
+
318
+ @pytest.mark.asyncio
319
+ async def test_queue_list_prints_empty_room_message(
320
+ monkeypatch: pytest.MonkeyPatch,
321
+ ) -> None:
322
+ account_client, printed, table_calls = await _run_queue_list(
323
+ monkeypatch=monkeypatch,
324
+ room_name="demo-room",
325
+ queues=[],
326
+ )
327
+
328
+ assert account_client.connect_calls == [
329
+ {"project_id": "project-1", "room": "demo-room"}
330
+ ]
331
+ assert account_client.closed is True
332
+ assert printed == ["There are no queues currently in the room"]
333
+ assert table_calls == []
334
+
335
+
336
+ @pytest.mark.asyncio
337
+ async def test_queue_list_json_output(
338
+ monkeypatch: pytest.MonkeyPatch,
339
+ ) -> None:
340
+ account_client, printed, table_calls = await _run_queue_list(
341
+ monkeypatch=monkeypatch,
342
+ room_name="demo-room",
343
+ queues=[_FakeQueue(name="jobs", size=3)],
344
+ output="json",
345
+ )
346
+
347
+ assert account_client.connect_calls == [
348
+ {"project_id": "project-1", "room": "demo-room"}
349
+ ]
350
+ assert account_client.closed is True
351
+ assert printed == [
352
+ '{\n "queues": [\n {\n "name": "jobs",\n "size": 3\n }\n ]\n}'
353
+ ]
354
+ assert table_calls == []
355
+
356
+
245
357
  @pytest.mark.asyncio
246
358
  async def test_size_prints_matching_queue_size(
247
359
  monkeypatch: pytest.MonkeyPatch,
@@ -0,0 +1 @@
1
+ __version__ = "0.34.0"
@@ -34,6 +34,7 @@ from meshagent.api.helpers import meshagent_base_url, websocket_room_url
34
34
  from meshagent.api.specs.service import (
35
35
  AgentSpec,
36
36
  ANNOTATION_AGENT_TYPE,
37
+ ANNOTATION_SERVICE_ID,
37
38
  ContainerMountSpec,
38
39
  EnvironmentVariable,
39
40
  PortSpec,
@@ -275,15 +276,17 @@ async def _upsert_domain_route(
275
276
  domain: str,
276
277
  room_name: str,
277
278
  port: str,
279
+ service_id: str,
278
280
  ) -> None:
279
281
  _warn_if_non_meshagent_app_domain(domain)
282
+ route_annotations = {ANNOTATION_SERVICE_ID: service_id}
280
283
  try:
281
284
  await client.create_route(
282
285
  project_id=project_id,
283
286
  domain=domain,
284
287
  room_name=room_name,
285
288
  port=port,
286
- annotations={},
289
+ annotations=route_annotations,
287
290
  )
288
291
  except ConflictError:
289
292
  existing = await client.get_route(project_id=project_id, domain=domain)
@@ -293,7 +296,9 @@ async def _upsert_domain_route(
293
296
  f"Refusing to change it to room {room_name}. "
294
297
  "Use `meshagent route update` if you want to repoint it."
295
298
  )
296
- if existing.port == port:
299
+ updated_annotations = dict(existing.annotations)
300
+ updated_annotations[ANNOTATION_SERVICE_ID] = service_id
301
+ if existing.port == port and existing.annotations == updated_annotations:
297
302
  print(f"[green]Route already configured:[/] {domain} -> {room_name}:{port}")
298
303
  return
299
304
  await client.update_route(
@@ -301,7 +306,7 @@ async def _upsert_domain_route(
301
306
  domain=domain,
302
307
  room_name=room_name,
303
308
  port=port,
304
- annotations=existing.annotations,
309
+ annotations=updated_annotations,
305
310
  )
306
311
  print(f"[green]Updated route:[/] {domain} -> {room_name}:{port}")
307
312
  else:
@@ -2057,6 +2062,7 @@ async def deploy(
2057
2062
  domain=domain,
2058
2063
  room_name=cast(str, room_name),
2059
2064
  port=str(resolved_web_port),
2065
+ service_id=resolved_service_name,
2060
2066
  )
2061
2067
 
2062
2068
  finally:
@@ -4,10 +4,133 @@ from pathlib import Path
4
4
  import pytest
5
5
  import typer
6
6
  from aiohttp.test_utils import TestClient, TestServer
7
+ from meshagent.api.client import ConflictError, Route
8
+ from meshagent.api.specs.service import ANNOTATION_SERVICE_ID
7
9
 
8
10
  from meshagent.cli import webserver
9
11
 
10
12
 
13
+ class _FakeRouteClient:
14
+ def __init__(
15
+ self,
16
+ *,
17
+ existing_route: Route | None = None,
18
+ create_conflict: bool = False,
19
+ ) -> None:
20
+ self._existing_route = existing_route
21
+ self._create_conflict = create_conflict
22
+ self.created_routes: list[dict[str, object]] = []
23
+ self.updated_routes: list[dict[str, object]] = []
24
+
25
+ async def create_route(
26
+ self,
27
+ *,
28
+ project_id: str,
29
+ domain: str,
30
+ room_name: str,
31
+ port: str,
32
+ annotations: dict[str, str],
33
+ ) -> None:
34
+ self.created_routes.append(
35
+ {
36
+ "project_id": project_id,
37
+ "domain": domain,
38
+ "room_name": room_name,
39
+ "port": port,
40
+ "annotations": annotations,
41
+ }
42
+ )
43
+ if self._create_conflict:
44
+ raise ConflictError("route already exists")
45
+
46
+ async def get_route(self, *, project_id: str, domain: str) -> Route:
47
+ assert self._existing_route is not None
48
+ assert project_id
49
+ assert domain
50
+ return self._existing_route
51
+
52
+ async def update_route(
53
+ self,
54
+ *,
55
+ project_id: str,
56
+ domain: str,
57
+ room_name: str,
58
+ port: str,
59
+ annotations: dict[str, str],
60
+ ) -> None:
61
+ self.updated_routes.append(
62
+ {
63
+ "project_id": project_id,
64
+ "domain": domain,
65
+ "room_name": room_name,
66
+ "port": port,
67
+ "annotations": annotations,
68
+ }
69
+ )
70
+
71
+
72
+ @pytest.mark.asyncio
73
+ async def test_upsert_domain_route_creates_route_with_service_id_annotation() -> None:
74
+ client = _FakeRouteClient()
75
+
76
+ await webserver._upsert_domain_route(
77
+ client=client,
78
+ project_id="project-123",
79
+ domain="site.meshagent.app",
80
+ room_name="demo-room",
81
+ port="8000",
82
+ service_id="demo-webserver",
83
+ )
84
+
85
+ assert client.created_routes == [
86
+ {
87
+ "project_id": "project-123",
88
+ "domain": "site.meshagent.app",
89
+ "room_name": "demo-room",
90
+ "port": "8000",
91
+ "annotations": {ANNOTATION_SERVICE_ID: "demo-webserver"},
92
+ }
93
+ ]
94
+ assert client.updated_routes == []
95
+
96
+
97
+ @pytest.mark.asyncio
98
+ async def test_upsert_domain_route_backfills_service_id_annotation_when_port_matches() -> (
99
+ None
100
+ ):
101
+ client = _FakeRouteClient(
102
+ create_conflict=True,
103
+ existing_route=Route(
104
+ domain="site.meshagent.app",
105
+ room_name="demo-room",
106
+ port="8000",
107
+ annotations={"meshagent.custom": "keep-me"},
108
+ ),
109
+ )
110
+
111
+ await webserver._upsert_domain_route(
112
+ client=client,
113
+ project_id="project-123",
114
+ domain="site.meshagent.app",
115
+ room_name="demo-room",
116
+ port="8000",
117
+ service_id="demo-webserver",
118
+ )
119
+
120
+ assert client.updated_routes == [
121
+ {
122
+ "project_id": "project-123",
123
+ "domain": "site.meshagent.app",
124
+ "room_name": "demo-room",
125
+ "port": "8000",
126
+ "annotations": {
127
+ "meshagent.custom": "keep-me",
128
+ ANNOTATION_SERVICE_ID: "demo-webserver",
129
+ },
130
+ }
131
+ ]
132
+
133
+
11
134
  async def _start_static_test_client(
12
135
  *,
13
136
  route_path: str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-cli
3
- Version: 0.33.2
3
+ Version: 0.34.0
4
4
  Summary: CLI for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -19,21 +19,21 @@ Requires-Dist: rich~=14.3.0
19
19
  Requires-Dist: textual<2.0,>=0.50
20
20
  Requires-Dist: prompt-toolkit~=3.0.52
21
21
  Provides-Extra: all
22
- Requires-Dist: meshagent-agents[all]~=0.33.2; extra == "all"
23
- Requires-Dist: meshagent-api[all]~=0.33.2; extra == "all"
24
- Requires-Dist: meshagent-computers~=0.33.2; extra == "all"
25
- Requires-Dist: meshagent-openai~=0.33.2; extra == "all"
26
- Requires-Dist: meshagent-anthropic~=0.33.2; extra == "all"
27
- Requires-Dist: meshagent-codex~=0.33.2; extra == "all"
28
- Requires-Dist: meshagent-mcp~=0.33.2; extra == "all"
29
- Requires-Dist: meshagent-tools~=0.33.2; extra == "all"
22
+ Requires-Dist: meshagent-agents[all]~=0.34.0; extra == "all"
23
+ Requires-Dist: meshagent-api[all]~=0.34.0; extra == "all"
24
+ Requires-Dist: meshagent-computers~=0.34.0; extra == "all"
25
+ Requires-Dist: meshagent-openai~=0.34.0; extra == "all"
26
+ Requires-Dist: meshagent-anthropic~=0.34.0; extra == "all"
27
+ Requires-Dist: meshagent-codex~=0.34.0; extra == "all"
28
+ Requires-Dist: meshagent-mcp~=0.34.0; extra == "all"
29
+ Requires-Dist: meshagent-tools~=0.34.0; extra == "all"
30
30
  Requires-Dist: supabase-auth~=2.28.0; extra == "all"
31
31
  Requires-Dist: prompt-toolkit~=3.0.52; extra == "all"
32
32
  Provides-Extra: mcp-service
33
- Requires-Dist: meshagent-agents[all]~=0.33.2; extra == "mcp-service"
34
- Requires-Dist: meshagent-api~=0.33.2; extra == "mcp-service"
35
- Requires-Dist: meshagent-mcp~=0.33.2; extra == "mcp-service"
36
- Requires-Dist: meshagent-tools~=0.33.2; extra == "mcp-service"
33
+ Requires-Dist: meshagent-agents[all]~=0.34.0; extra == "mcp-service"
34
+ Requires-Dist: meshagent-api~=0.34.0; extra == "mcp-service"
35
+ Requires-Dist: meshagent-mcp~=0.34.0; extra == "mcp-service"
36
+ Requires-Dist: meshagent-tools~=0.34.0; extra == "mcp-service"
37
37
  Requires-Dist: supabase-auth~=2.28.0; extra == "mcp-service"
38
38
 
39
39
  # [Meshagent](https://www.meshagent.com)
@@ -0,0 +1,29 @@
1
+ typer~=0.21
2
+ fastmcp~=2.8
3
+ opentelemetry-distro~=0.59b0
4
+ opentelemetry-exporter-otlp-proto-http~=1.33
5
+ art~=6.5
6
+ pydantic-yaml~=1.5
7
+ pathspec~=0.12.1
8
+ rich~=14.3.0
9
+ textual<2.0,>=0.50
10
+ prompt-toolkit~=3.0.52
11
+
12
+ [all]
13
+ meshagent-agents[all]~=0.34.0
14
+ meshagent-api[all]~=0.34.0
15
+ meshagent-computers~=0.34.0
16
+ meshagent-openai~=0.34.0
17
+ meshagent-anthropic~=0.34.0
18
+ meshagent-codex~=0.34.0
19
+ meshagent-mcp~=0.34.0
20
+ meshagent-tools~=0.34.0
21
+ supabase-auth~=2.28.0
22
+ prompt-toolkit~=3.0.52
23
+
24
+ [mcp-service]
25
+ meshagent-agents[all]~=0.34.0
26
+ meshagent-api~=0.34.0
27
+ meshagent-mcp~=0.34.0
28
+ meshagent-tools~=0.34.0
29
+ supabase-auth~=2.28.0
@@ -26,23 +26,23 @@ dynamic = ["version", "readme"]
26
26
  [project.optional-dependencies]
27
27
 
28
28
  all = [
29
- "meshagent-agents[all]~=0.33.2",
30
- "meshagent-api[all]~=0.33.2",
31
- "meshagent-computers~=0.33.2",
32
- "meshagent-openai~=0.33.2",
33
- "meshagent-anthropic~=0.33.2",
34
- "meshagent-codex~=0.33.2",
35
- "meshagent-mcp~=0.33.2",
36
- "meshagent-tools~=0.33.2",
29
+ "meshagent-agents[all]~=0.34.0",
30
+ "meshagent-api[all]~=0.34.0",
31
+ "meshagent-computers~=0.34.0",
32
+ "meshagent-openai~=0.34.0",
33
+ "meshagent-anthropic~=0.34.0",
34
+ "meshagent-codex~=0.34.0",
35
+ "meshagent-mcp~=0.34.0",
36
+ "meshagent-tools~=0.34.0",
37
37
  "supabase-auth~=2.28.0",
38
38
  "prompt-toolkit~=3.0.52"
39
39
  ]
40
40
 
41
41
  mcp-service = [
42
- "meshagent-agents[all]~=0.33.2",
43
- "meshagent-api~=0.33.2",
44
- "meshagent-mcp~=0.33.2",
45
- "meshagent-tools~=0.33.2",
42
+ "meshagent-agents[all]~=0.34.0",
43
+ "meshagent-api~=0.34.0",
44
+ "meshagent-mcp~=0.34.0",
45
+ "meshagent-tools~=0.34.0",
46
46
  "supabase-auth~=2.28.0"
47
47
  ]
48
48
 
@@ -1 +0,0 @@
1
- __version__ = "0.33.2"
@@ -1,29 +0,0 @@
1
- typer~=0.21
2
- fastmcp~=2.8
3
- opentelemetry-distro~=0.59b0
4
- opentelemetry-exporter-otlp-proto-http~=1.33
5
- art~=6.5
6
- pydantic-yaml~=1.5
7
- pathspec~=0.12.1
8
- rich~=14.3.0
9
- textual<2.0,>=0.50
10
- prompt-toolkit~=3.0.52
11
-
12
- [all]
13
- meshagent-agents[all]~=0.33.2
14
- meshagent-api[all]~=0.33.2
15
- meshagent-computers~=0.33.2
16
- meshagent-openai~=0.33.2
17
- meshagent-anthropic~=0.33.2
18
- meshagent-codex~=0.33.2
19
- meshagent-mcp~=0.33.2
20
- meshagent-tools~=0.33.2
21
- supabase-auth~=2.28.0
22
- prompt-toolkit~=3.0.52
23
-
24
- [mcp-service]
25
- meshagent-agents[all]~=0.33.2
26
- meshagent-api~=0.33.2
27
- meshagent-mcp~=0.33.2
28
- meshagent-tools~=0.33.2
29
- supabase-auth~=2.28.0
File without changes
File without changes