meshagent-api 0.24.6__tar.gz → 0.25.1__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.
- {meshagent_api-0.24.6/meshagent_api.egg-info → meshagent_api-0.25.1}/PKG-INFO +3 -2
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/client.py +37 -9
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/helpers.py +7 -2
- meshagent_api-0.25.1/meshagent/api/http.py +14 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/participant_token.py +7 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/port_forward.py +2 -1
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/room_server_client.py +359 -308
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/specs/service.py +126 -27
- meshagent_api-0.25.1/meshagent/api/sql.py +223 -0
- meshagent_api-0.25.1/meshagent/api/sql_test.py +38 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/urls.py +1 -1
- meshagent_api-0.25.1/meshagent/api/version.py +1 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/websocket_protocol.py +18 -4
- {meshagent_api-0.24.6 → meshagent_api-0.25.1/meshagent_api.egg-info}/PKG-INFO +3 -2
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent_api.egg-info/SOURCES.txt +3 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent_api.egg-info/requires.txt +2 -1
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/pyproject.toml +3 -2
- meshagent_api-0.24.6/meshagent/api/version.py +0 -1
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/LICENSE +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/MANIFEST.in +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/README.md +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/__init__.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/chan.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/crdt.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/entrypoint.js +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/keys.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/messaging.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/oauth.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/participant.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/participant_token_test.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/protocol.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/protocol_test.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/py.typed +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/reasoning_schema.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/runtime.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/runtime_test.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/schema.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/schema_document.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/schema_document_test.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/schema_registry.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/schema_test.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/schema_util.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/service_template_test.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/services.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/token_test.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent/api/webhooks.py +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent_api.egg-info/dependency_links.txt +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/meshagent_api.egg-info/top_level.txt +0 -0
- {meshagent_api-0.24.6 → meshagent_api-0.25.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshagent-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.1
|
|
4
4
|
Summary: Python Server API for Meshagent
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Documentation, https://docs.meshagent.com
|
|
@@ -10,12 +10,13 @@ Requires-Python: >=3.13
|
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Requires-Dist: pyjwt~=2.10
|
|
13
|
-
Requires-Dist: aiohttp~=3.
|
|
13
|
+
Requires-Dist: aiohttp[speedups]~=3.13.0
|
|
14
14
|
Requires-Dist: jsonschema~=4.23
|
|
15
15
|
Requires-Dist: pycrdt~=0.12.26
|
|
16
16
|
Requires-Dist: opentelemetry-distro~=0.54b1
|
|
17
17
|
Requires-Dist: pydantic~=2.11.7
|
|
18
18
|
Requires-Dist: jinja2~=3.1.6
|
|
19
|
+
Requires-Dist: certifi~=2026.1.4
|
|
19
20
|
Provides-Extra: all
|
|
20
21
|
Provides-Extra: sync
|
|
21
22
|
Provides-Extra: stpyv8
|
|
@@ -4,6 +4,7 @@ from pydantic import BaseModel, ValidationError, JsonValue, Field, ConfigDict
|
|
|
4
4
|
from meshagent.api import RoomException
|
|
5
5
|
from meshagent.api.participant_token import ApiScope
|
|
6
6
|
from meshagent.api.helpers import meshagent_base_url
|
|
7
|
+
from meshagent.api.http import new_client_session
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from meshagent.api.specs.service import (
|
|
9
10
|
ServiceSpec,
|
|
@@ -314,6 +315,7 @@ class Meshagent:
|
|
|
314
315
|
*,
|
|
315
316
|
base_url: str = meshagent_base_url(),
|
|
316
317
|
token: str = os.getenv("MESHAGENT_API_KEY"),
|
|
318
|
+
session: aiohttp.ClientSession | None = None,
|
|
317
319
|
):
|
|
318
320
|
"""
|
|
319
321
|
:param base_url: The root URL of your server, e.g. 'http://localhost:8080'.
|
|
@@ -321,11 +323,11 @@ class Meshagent:
|
|
|
321
323
|
"""
|
|
322
324
|
self.base_url = base_url.rstrip("/")
|
|
323
325
|
self.token = token # The "Bearer" token
|
|
324
|
-
|
|
325
|
-
self._session =
|
|
326
|
+
self._session_external = session is not None
|
|
327
|
+
self._session = session or new_client_session()
|
|
326
328
|
|
|
327
329
|
async def close(self):
|
|
328
|
-
if not self._session.closed:
|
|
330
|
+
if not self._session_external and not self._session.closed:
|
|
329
331
|
await self._session.close()
|
|
330
332
|
|
|
331
333
|
async def __aenter__(self):
|
|
@@ -592,6 +594,32 @@ class Meshagent:
|
|
|
592
594
|
await self._raise_for_status(resp)
|
|
593
595
|
return await resp.json()
|
|
594
596
|
|
|
597
|
+
async def update_project_user(
|
|
598
|
+
self,
|
|
599
|
+
project_id: str,
|
|
600
|
+
user_id: str,
|
|
601
|
+
*,
|
|
602
|
+
is_admin: bool,
|
|
603
|
+
is_developer: bool,
|
|
604
|
+
can_create_rooms: bool,
|
|
605
|
+
) -> Dict[str, Any]:
|
|
606
|
+
"""
|
|
607
|
+
Corresponds to: PUT /accounts/projects/:project_id/users/:user_id
|
|
608
|
+
Body: { "is_admin", "is_developer", "can_create_rooms" }
|
|
609
|
+
Returns a JSON dict with { "ok": True } on success.
|
|
610
|
+
"""
|
|
611
|
+
url = f"{self.base_url}/accounts/projects/{project_id}/users/{user_id}"
|
|
612
|
+
body = {
|
|
613
|
+
"is_admin": is_admin,
|
|
614
|
+
"is_developer": is_developer,
|
|
615
|
+
"can_create_rooms": can_create_rooms,
|
|
616
|
+
}
|
|
617
|
+
async with self._session.put(
|
|
618
|
+
url, headers=self._get_headers(), json=body
|
|
619
|
+
) as resp:
|
|
620
|
+
await self._raise_for_status(resp)
|
|
621
|
+
return await resp.json()
|
|
622
|
+
|
|
595
623
|
async def update_project_settings(
|
|
596
624
|
self, project_id: str, settings: dict
|
|
597
625
|
) -> Dict[str, Any]:
|
|
@@ -1377,7 +1405,7 @@ class Meshagent:
|
|
|
1377
1405
|
*,
|
|
1378
1406
|
project_id: str,
|
|
1379
1407
|
room_name: str,
|
|
1380
|
-
template:
|
|
1408
|
+
template: str,
|
|
1381
1409
|
values: Dict[str, str],
|
|
1382
1410
|
) -> ServiceSpec:
|
|
1383
1411
|
"""
|
|
@@ -1402,12 +1430,12 @@ class Meshagent:
|
|
|
1402
1430
|
url,
|
|
1403
1431
|
headers=self._get_headers(),
|
|
1404
1432
|
json={
|
|
1405
|
-
"template": template
|
|
1433
|
+
"template": template,
|
|
1406
1434
|
"values": values,
|
|
1407
1435
|
},
|
|
1408
1436
|
) as resp:
|
|
1409
1437
|
await self._raise_for_status(resp)
|
|
1410
|
-
return ServiceSpec.
|
|
1438
|
+
return ServiceSpec.model_validate(await resp.json())
|
|
1411
1439
|
|
|
1412
1440
|
async def update_room_service_from_template(
|
|
1413
1441
|
self,
|
|
@@ -1415,7 +1443,7 @@ class Meshagent:
|
|
|
1415
1443
|
project_id: str,
|
|
1416
1444
|
room_name: str,
|
|
1417
1445
|
service_id: str,
|
|
1418
|
-
template:
|
|
1446
|
+
template: str,
|
|
1419
1447
|
values: Dict[str, str],
|
|
1420
1448
|
) -> ServiceSpec:
|
|
1421
1449
|
"""
|
|
@@ -1429,12 +1457,12 @@ class Meshagent:
|
|
|
1429
1457
|
url,
|
|
1430
1458
|
headers=self._get_headers(),
|
|
1431
1459
|
json={
|
|
1432
|
-
"template": template
|
|
1460
|
+
"template": template,
|
|
1433
1461
|
"values": values,
|
|
1434
1462
|
},
|
|
1435
1463
|
) as resp:
|
|
1436
1464
|
await self._raise_for_status(resp)
|
|
1437
|
-
return ServiceSpec.
|
|
1465
|
+
return ServiceSpec.model_validate(await resp.json())
|
|
1438
1466
|
|
|
1439
1467
|
async def get_room_service(
|
|
1440
1468
|
self, *, project_id: str, room_name: str, service_id: str
|
|
@@ -3,6 +3,7 @@ import json
|
|
|
3
3
|
from .participant_token import ParticipantToken, ApiScope
|
|
4
4
|
from typing import Optional
|
|
5
5
|
import os
|
|
6
|
+
import aiohttp
|
|
6
7
|
from .websocket_protocol import WebSocketClientProtocol
|
|
7
8
|
import re
|
|
8
9
|
from warnings import deprecated
|
|
@@ -68,7 +69,11 @@ def participant_token(
|
|
|
68
69
|
|
|
69
70
|
@deprecated("create WebSocketClientProtocol directly instead")
|
|
70
71
|
def websocket_protocol(
|
|
71
|
-
*,
|
|
72
|
+
*,
|
|
73
|
+
participant_name: str,
|
|
74
|
+
room_name: str,
|
|
75
|
+
role: Optional[str] = None,
|
|
76
|
+
session: aiohttp.ClientSession | None = None,
|
|
72
77
|
):
|
|
73
78
|
url = websocket_room_url(room_name=room_name)
|
|
74
79
|
token_jwt = os.getenv("MESHAGENT_TOKEN", None)
|
|
@@ -78,7 +83,7 @@ def websocket_protocol(
|
|
|
78
83
|
)
|
|
79
84
|
token_jwt = token.to_jwt(token=os.getenv("MESHAGENT_SECRET"))
|
|
80
85
|
|
|
81
|
-
return WebSocketClientProtocol(url=url, token=token_jwt)
|
|
86
|
+
return WebSocketClientProtocol(url=url, token=token_jwt, session=session)
|
|
82
87
|
|
|
83
88
|
|
|
84
89
|
# Pre-compile the pattern once if you’ll call this many times
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
import ssl
|
|
5
|
+
|
|
6
|
+
from aiohttp import ClientSession, TCPConnector
|
|
7
|
+
import certifi
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def new_client_session(*args: Any, **kwargs: Any) -> ClientSession:
|
|
11
|
+
if "connector" not in kwargs:
|
|
12
|
+
ssl_context = ssl.create_default_context(cafile=certifi.where())
|
|
13
|
+
kwargs["connector"] = TCPConnector(ssl=ssl_context)
|
|
14
|
+
return ClientSession(*args, **kwargs)
|
|
@@ -227,6 +227,10 @@ class TunnelsGrant(BaseModel):
|
|
|
227
227
|
ports: Optional[list[str]] = None
|
|
228
228
|
|
|
229
229
|
|
|
230
|
+
class ServicesGrant(BaseModel):
|
|
231
|
+
list: bool = True
|
|
232
|
+
|
|
233
|
+
|
|
230
234
|
class ApiScope(BaseModel):
|
|
231
235
|
livekit: Optional[LivekitGrant] = None
|
|
232
236
|
queues: Optional[QueuesGrant] = None
|
|
@@ -240,6 +244,7 @@ class ApiScope(BaseModel):
|
|
|
240
244
|
admin: Optional[AdminGrant] = None
|
|
241
245
|
secrets: Optional[SecretsGrant] = None
|
|
242
246
|
tunnels: Optional[TunnelsGrant] = None
|
|
247
|
+
services: Optional[ServicesGrant] = None
|
|
243
248
|
|
|
244
249
|
# no secrets access, no admin access by default for agents
|
|
245
250
|
@staticmethod
|
|
@@ -254,6 +259,7 @@ class ApiScope(BaseModel):
|
|
|
254
259
|
containers=ContainersGrant(),
|
|
255
260
|
developer=DeveloperGrant(),
|
|
256
261
|
agents=AgentsGrant(),
|
|
262
|
+
services=ServicesGrant(),
|
|
257
263
|
tunnels=TunnelsGrant() if tunnels else None,
|
|
258
264
|
)
|
|
259
265
|
|
|
@@ -272,6 +278,7 @@ class ApiScope(BaseModel):
|
|
|
272
278
|
admin=AdminGrant(),
|
|
273
279
|
secrets=SecretsGrant(),
|
|
274
280
|
tunnels=TunnelsGrant(),
|
|
281
|
+
services=ServicesGrant(),
|
|
275
282
|
)
|
|
276
283
|
|
|
277
284
|
|
|
@@ -7,6 +7,7 @@ from dataclasses import dataclass
|
|
|
7
7
|
import aiohttp
|
|
8
8
|
|
|
9
9
|
from meshagent.api.helpers import meshagent_base_url
|
|
10
|
+
from meshagent.api.http import new_client_session
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@dataclass
|
|
@@ -60,7 +61,7 @@ async def port_forward(
|
|
|
60
61
|
sock_read=None,
|
|
61
62
|
)
|
|
62
63
|
|
|
63
|
-
session =
|
|
64
|
+
session = new_client_session(timeout=timeout)
|
|
64
65
|
|
|
65
66
|
async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
|
|
66
67
|
ws: aiohttp.ClientWebSocketResponse | None = None
|