libentry 1.23.1__py3-none-any.whl → 1.23.3__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.
- libentry/mcp/client.py +57 -22
- libentry/schema.py +4 -2
- {libentry-1.23.1.dist-info → libentry-1.23.3.dist-info}/METADATA +1 -1
- {libentry-1.23.1.dist-info → libentry-1.23.3.dist-info}/RECORD +9 -9
- {libentry-1.23.1.dist-info → libentry-1.23.3.dist-info}/LICENSE +0 -0
- {libentry-1.23.1.dist-info → libentry-1.23.3.dist-info}/WHEEL +0 -0
- {libentry-1.23.1.dist-info → libentry-1.23.3.dist-info}/entry_points.txt +0 -0
- {libentry-1.23.1.dist-info → libentry-1.23.3.dist-info}/top_level.txt +0 -0
- {libentry-1.23.1.dist-info → libentry-1.23.3.dist-info}/zip-safe +0 -0
libentry/mcp/client.py
CHANGED
@@ -244,6 +244,9 @@ class MCPMixIn(JSONRPCMixIn, abc.ABC):
|
|
244
244
|
|
245
245
|
return InitializeResult.model_validate(result)
|
246
246
|
|
247
|
+
def ping(self):
|
248
|
+
return self.call("ping")
|
249
|
+
|
247
250
|
def list_tools(self) -> ListToolsResult:
|
248
251
|
result = self.call("tools/list")
|
249
252
|
return ListToolsResult.model_validate(result)
|
@@ -530,51 +533,83 @@ class APIClient(SubroutineMixIn, MCPMixIn):
|
|
530
533
|
|
531
534
|
class SSESession(MCPMixIn):
|
532
535
|
|
533
|
-
def __init__(self, client: APIClient, sse_endpoint: str):
|
536
|
+
def __init__(self, client: APIClient, sse_endpoint: str, sse_timeout: int = 6):
|
534
537
|
self.client = client
|
535
538
|
self.sse_endpoint = sse_endpoint
|
536
|
-
|
537
|
-
self.sse_thread = Thread(target=self._sse_loop, daemon=True)
|
538
|
-
self.sse_thread.start()
|
539
|
+
self.sse_timeout = sse_timeout
|
539
540
|
|
540
541
|
self.lock = Semaphore(0)
|
541
542
|
self.endpoint = None
|
542
543
|
self.pendings = {}
|
544
|
+
self.closed = False
|
545
|
+
|
546
|
+
self.ping_thread = Thread(target=self._ping_loop, daemon=False)
|
547
|
+
self.ping_thread.start()
|
548
|
+
|
549
|
+
self.sse_thread = Thread(target=self._sse_loop, daemon=False)
|
550
|
+
self.sse_thread.start()
|
551
|
+
|
552
|
+
def __enter__(self):
|
553
|
+
return self
|
554
|
+
|
555
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
556
|
+
self.close()
|
557
|
+
|
558
|
+
def close(self):
|
559
|
+
with self.lock:
|
560
|
+
self.closed = True
|
561
|
+
|
562
|
+
def _ping_loop(self):
|
563
|
+
interval = max(self.sse_timeout / 2, 0.5)
|
564
|
+
while True:
|
565
|
+
with self.lock:
|
566
|
+
if self.closed:
|
567
|
+
break
|
568
|
+
sleep(interval)
|
569
|
+
self.ping()
|
543
570
|
|
544
571
|
def _sse_loop(self):
|
545
572
|
request = HTTPRequest(
|
546
573
|
path=self.sse_endpoint,
|
547
574
|
options=HTTPOptions(
|
548
575
|
method="GET",
|
549
|
-
timeout=
|
576
|
+
timeout=self.sse_timeout
|
550
577
|
)
|
551
578
|
)
|
552
579
|
response = self.client.http_request(request)
|
553
580
|
assert response.stream
|
554
581
|
type_adapter = TypeAdapter(Union[JSONRPCRequest, JSONRPCResponse, JSONRPCNotification])
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
582
|
+
try:
|
583
|
+
for sse in response.content:
|
584
|
+
assert isinstance(sse, SSE)
|
585
|
+
if sse.event == "endpoint":
|
586
|
+
self.endpoint = sse.data
|
587
|
+
self.lock.release()
|
588
|
+
elif sse.event == "message":
|
589
|
+
json_obj = json.loads(sse.data)
|
590
|
+
obj = type_adapter.validate_python(json_obj)
|
591
|
+
if isinstance(obj, JSONRPCRequest):
|
592
|
+
self._on_request(obj)
|
593
|
+
elif isinstance(obj, JSONRPCNotification):
|
594
|
+
self._on_notification(obj)
|
595
|
+
elif isinstance(obj, JSONRPCResponse):
|
596
|
+
self._on_response(obj)
|
597
|
+
else:
|
598
|
+
pass
|
569
599
|
else:
|
570
|
-
|
571
|
-
|
572
|
-
|
600
|
+
raise RuntimeError(f"Unknown event {sse.event}.")
|
601
|
+
with self.lock:
|
602
|
+
if self.closed:
|
603
|
+
break
|
604
|
+
except httpx.Timeout:
|
605
|
+
pass
|
573
606
|
|
574
607
|
def _on_request(self, request: JSONRPCRequest):
|
608
|
+
print(request)
|
575
609
|
pass
|
576
610
|
|
577
611
|
def _on_notification(self, notification: JSONRPCNotification):
|
612
|
+
print(notification)
|
578
613
|
pass
|
579
614
|
|
580
615
|
def _on_response(self, response: JSONRPCResponse):
|
libentry/schema.py
CHANGED
@@ -152,7 +152,8 @@ def _parse_dict(context: ParseContext) -> Optional[str]:
|
|
152
152
|
key_type = "str"
|
153
153
|
value_type = parse_type(dict_args[1], context.schemas)
|
154
154
|
if isinstance(value_type, list):
|
155
|
-
|
155
|
+
value_type = "|".join(value_type)
|
156
|
+
# raise TypeError("\"Union\" cannot be used as the type of dict elements.")
|
156
157
|
return f"Dict[{key_type},{value_type}]"
|
157
158
|
else:
|
158
159
|
return "Dict"
|
@@ -168,7 +169,8 @@ def _parse_list(context: ParseContext) -> Optional[str]:
|
|
168
169
|
raise TypeError("Only ONE type can be used as the type of list elements.")
|
169
170
|
elem_type = parse_type(list_args[0], context.schemas)
|
170
171
|
if isinstance(elem_type, list):
|
171
|
-
|
172
|
+
elem_type = "|".join(elem_type)
|
173
|
+
# raise TypeError("\"Union\" cannot be used as the type of list elements.")
|
172
174
|
return f"List[{elem_type}]"
|
173
175
|
else:
|
174
176
|
return "List"
|
@@ -6,12 +6,12 @@ libentry/executor.py,sha256=cTV0WxJi0nU1TP-cOwmeodN8DD6L1691M2HIQsJtGrU,6582
|
|
6
6
|
libentry/experiment.py,sha256=ejgAHDXWIe9x4haUzIFuz1WasLY0_aD1z_vyEVGjTu8,4922
|
7
7
|
libentry/json.py,sha256=CubUUu29h7idLaC4d66vKhjBgVHKN1rZOv-Tw2qM17k,1916
|
8
8
|
libentry/logging.py,sha256=IiYoCUzm8XTK1fduA-NA0FI2Qz_m81NEPV3d3tEfgdI,1349
|
9
|
-
libentry/schema.py,sha256=
|
9
|
+
libentry/schema.py,sha256=40SOhCF_eytWOF47MWKCRHKHl_lCaQVetx1Af62PkiI,10439
|
10
10
|
libentry/test_api.py,sha256=Xw7B7sH6g1iCTV5sFzyBF3JAJzeOr9xg0AyezTNsnIk,4452
|
11
11
|
libentry/utils.py,sha256=O7P6GadtUIjq0N2IZH7PhHZDUM3NebzcqyDqytet7CM,683
|
12
12
|
libentry/mcp/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
|
13
13
|
libentry/mcp/api.py,sha256=uoGBYCesMj6umlJpRulKZNS3trm9oG3LUSg1otPDS_8,2362
|
14
|
-
libentry/mcp/client.py,sha256=
|
14
|
+
libentry/mcp/client.py,sha256=tEJbMpXiMKQ0qDgLGyavE2A4jpoXliqbrVj_TMfOGXI,22488
|
15
15
|
libentry/mcp/service.py,sha256=KDpEUhHuyVXjc_J5Z9_aciJbTcEy9dYA44rpdgAAwGE,32322
|
16
16
|
libentry/mcp/types.py,sha256=xTQCnKAgeJNss4klJ33MrWHGCzG_LeR3urizO_Z9q9U,12239
|
17
17
|
libentry/service/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
|
@@ -21,10 +21,10 @@ libentry/service/list.py,sha256=ElHWhTgShGOhaxMUEwVbMXos0NQKjHsODboiQ-3AMwE,1397
|
|
21
21
|
libentry/service/running.py,sha256=FrPJoJX6wYxcHIysoatAxhW3LajCCm0Gx6l7__6sULQ,5105
|
22
22
|
libentry/service/start.py,sha256=mZT7b9rVULvzy9GTZwxWnciCHgv9dbGN2JbxM60OMn4,1270
|
23
23
|
libentry/service/stop.py,sha256=wOpwZgrEJ7QirntfvibGq-XsTC6b3ELhzRW2zezh-0s,1187
|
24
|
-
libentry-1.23.
|
25
|
-
libentry-1.23.
|
26
|
-
libentry-1.23.
|
27
|
-
libentry-1.23.
|
28
|
-
libentry-1.23.
|
29
|
-
libentry-1.23.
|
30
|
-
libentry-1.23.
|
24
|
+
libentry-1.23.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
25
|
+
libentry-1.23.3.dist-info/METADATA,sha256=5AIjlPrO1Q8nWDiCZNN5S4qo8jZCqNXD_twACQuw0T0,1135
|
26
|
+
libentry-1.23.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
27
|
+
libentry-1.23.3.dist-info/entry_points.txt,sha256=1v_nLVDsjvVJp9SWhl4ef2zZrsLTBtFWgrYFgqvQBgc,61
|
28
|
+
libentry-1.23.3.dist-info/top_level.txt,sha256=u2uF6-X5fn2Erf9PYXOg_6tntPqTpyT-yzUZrltEd6I,9
|
29
|
+
libentry-1.23.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
30
|
+
libentry-1.23.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|