lmrs-client 0.1.4__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.
lmrs_client/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""LMRS client library.
|
|
2
|
+
|
|
3
|
+
Gives external consumers full access to the LMRS public command surface with
|
|
4
|
+
transport, protocol selection, connection management, serialization and error
|
|
5
|
+
mapping encapsulated by the ``mcp_proxy_adapter`` framework client.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from lmrs_client.client import LmrsClient
|
|
9
|
+
|
|
10
|
+
__all__ = ["LmrsClient"]
|
lmrs_client/client.py
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""The LMRS client: one method per public LMRS command.
|
|
2
|
+
|
|
3
|
+
Wraps the ``mcp_proxy_adapter`` framework JSON-RPC client. No method builds a
|
|
4
|
+
URL, a JSON-RPC envelope or a raw transport payload: transport, protocol
|
|
5
|
+
selection, connection management, serialization and error mapping all belong to
|
|
6
|
+
the framework client. Queued commands are driven to completion through the
|
|
7
|
+
framework's queued-job facility rather than by polling here.
|
|
8
|
+
|
|
9
|
+
The client never defines the API. Every method mirrors a command the server
|
|
10
|
+
registers, with the same name, so client and server can be read against each
|
|
11
|
+
other without a translation table.
|
|
12
|
+
|
|
13
|
+
Author: Vasiliy Zdanovskiy
|
|
14
|
+
email: vasilyvz@gmail.com
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from mcp_proxy_adapter.client.jsonrpc_client.client import JsonRpcClient
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LmrsClient:
|
|
25
|
+
"""Full-surface client for one LMRS server.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
transport: The framework JSON-RPC client carrying every request.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
host: str = "127.0.0.1",
|
|
34
|
+
port: int = 8012,
|
|
35
|
+
protocol: str = "https",
|
|
36
|
+
*,
|
|
37
|
+
token: str | None = None,
|
|
38
|
+
token_header: str | None = None,
|
|
39
|
+
cert: str | None = None,
|
|
40
|
+
key: str | None = None,
|
|
41
|
+
ca: str | None = None,
|
|
42
|
+
check_hostname: bool = False,
|
|
43
|
+
timeout: float | None = None,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Build a client bound to one LMRS server.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
host: Server hostname.
|
|
49
|
+
port: Server port.
|
|
50
|
+
protocol: Transport protocol: ``http``, ``https`` or ``mtls``.
|
|
51
|
+
token: Authentication token value, when the server requires one.
|
|
52
|
+
token_header: Header carrying the token.
|
|
53
|
+
cert: Client certificate path for mTLS.
|
|
54
|
+
key: Client private key path for mTLS.
|
|
55
|
+
ca: CA certificate path.
|
|
56
|
+
check_hostname: Whether TLS verifies the hostname.
|
|
57
|
+
timeout: Request timeout in seconds; the framework default applies
|
|
58
|
+
when omitted.
|
|
59
|
+
"""
|
|
60
|
+
self.transport = JsonRpcClient(
|
|
61
|
+
protocol=protocol,
|
|
62
|
+
host=host,
|
|
63
|
+
port=port,
|
|
64
|
+
token=token,
|
|
65
|
+
token_header=token_header,
|
|
66
|
+
cert=cert,
|
|
67
|
+
key=key,
|
|
68
|
+
ca=ca,
|
|
69
|
+
check_hostname=check_hostname,
|
|
70
|
+
timeout=timeout,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
async def _call(self, command: str, params: dict[str, Any] | None = None, *, queued: bool = False) -> Any:
|
|
74
|
+
"""Send one command through the framework client.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
command: Public command name, as registered by the server.
|
|
78
|
+
params: Command parameters, omitted when the command takes none.
|
|
79
|
+
queued: True for a command the server runs through its queue; the
|
|
80
|
+
framework then waits for the job to finish instead of returning
|
|
81
|
+
a job id for the caller to poll.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
The command result the server produced.
|
|
85
|
+
"""
|
|
86
|
+
return await self.transport.execute_command_unified(
|
|
87
|
+
command,
|
|
88
|
+
params or {},
|
|
89
|
+
expect_queue=True if queued else False,
|
|
90
|
+
auto_poll=True,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
async def healthcheck(self) -> Any:
|
|
94
|
+
"""Report adapter health.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
The healthcheck result.
|
|
98
|
+
"""
|
|
99
|
+
return await self._call("healthcheck")
|
|
100
|
+
|
|
101
|
+
async def info(self) -> Any:
|
|
102
|
+
"""Describe service identity, build, runtime and capabilities.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The info payload.
|
|
106
|
+
"""
|
|
107
|
+
return await self._call("info")
|
|
108
|
+
|
|
109
|
+
async def model_status(self, model_name: str) -> Any:
|
|
110
|
+
"""Report the memory residency status of a model.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
model_name: Name of the model to inspect.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
The model status result.
|
|
117
|
+
"""
|
|
118
|
+
return await self._call("model_status", {"model_name": model_name})
|
|
119
|
+
|
|
120
|
+
async def capacity(self) -> Any:
|
|
121
|
+
"""Report measured VRAM facts and the usable dynamic pool.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
The capacity snapshot.
|
|
125
|
+
"""
|
|
126
|
+
return await self._call("capacity")
|
|
127
|
+
|
|
128
|
+
async def token_count(
|
|
129
|
+
self,
|
|
130
|
+
input_tokens: int,
|
|
131
|
+
tokenizer_name: str,
|
|
132
|
+
tokenizer_accuracy: str,
|
|
133
|
+
*,
|
|
134
|
+
tool_tokens: int = 0,
|
|
135
|
+
service_tokens: int = 0,
|
|
136
|
+
reserved_output_tokens: int = 0,
|
|
137
|
+
rough_estimate: bool = False,
|
|
138
|
+
) -> Any:
|
|
139
|
+
"""Report the token breakdown and required tokens of a request.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
input_tokens: Tokens in the input prompt.
|
|
143
|
+
tokenizer_name: Name of the tokenizer that produced the counts.
|
|
144
|
+
tokenizer_accuracy: Accuracy descriptor for the counts.
|
|
145
|
+
tool_tokens: Tokens consumed by tool definitions.
|
|
146
|
+
service_tokens: Tokens consumed by system service instructions.
|
|
147
|
+
reserved_output_tokens: Output tokens reserved for generation.
|
|
148
|
+
rough_estimate: Whether the counts are a rough estimate.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
The token breakdown and the required token total.
|
|
152
|
+
"""
|
|
153
|
+
return await self._call(
|
|
154
|
+
"token_count",
|
|
155
|
+
{
|
|
156
|
+
"input_tokens": input_tokens,
|
|
157
|
+
"tokenizer_name": tokenizer_name,
|
|
158
|
+
"tokenizer_accuracy": tokenizer_accuracy,
|
|
159
|
+
"tool_tokens": tool_tokens,
|
|
160
|
+
"service_tokens": service_tokens,
|
|
161
|
+
"reserved_output_tokens": reserved_output_tokens,
|
|
162
|
+
"rough_estimate": rough_estimate,
|
|
163
|
+
},
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
async def estimate(self, **request: Any) -> Any:
|
|
167
|
+
"""Report whether a request would execute, queue or be rejected.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
**request: The estimate inputs the server's estimate schema
|
|
171
|
+
declares: request_id, model_name, token_breakdown,
|
|
172
|
+
declared_context_window, capacity, kv_bytes_per_token,
|
|
173
|
+
per_request_overhead_bytes and runtime_batch_overhead_bytes.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
The dry-run outcome with its reason code.
|
|
177
|
+
"""
|
|
178
|
+
return await self._call("estimate", dict(request))
|
|
179
|
+
|
|
180
|
+
async def chat(
|
|
181
|
+
self,
|
|
182
|
+
message: str,
|
|
183
|
+
model_name: str,
|
|
184
|
+
*,
|
|
185
|
+
system: str | None = None,
|
|
186
|
+
temperature: float | None = None,
|
|
187
|
+
max_tokens: int | None = None,
|
|
188
|
+
) -> Any:
|
|
189
|
+
"""Send a chat message to the locally served model.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
message: The user message.
|
|
193
|
+
model_name: Model to serve the request.
|
|
194
|
+
system: Optional system instruction.
|
|
195
|
+
temperature: Optional sampling temperature.
|
|
196
|
+
max_tokens: Optional output token limit.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
The chat result.
|
|
200
|
+
"""
|
|
201
|
+
params: dict[str, Any] = {"message": message, "model_name": model_name}
|
|
202
|
+
if system is not None:
|
|
203
|
+
params["system"] = system
|
|
204
|
+
if temperature is not None:
|
|
205
|
+
params["temperature"] = temperature
|
|
206
|
+
if max_tokens is not None:
|
|
207
|
+
params["max_tokens"] = max_tokens
|
|
208
|
+
return await self._call("chat", params)
|
|
209
|
+
|
|
210
|
+
async def queue_status(self) -> Any:
|
|
211
|
+
"""Report the current request queue state.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
The queue entries.
|
|
215
|
+
"""
|
|
216
|
+
return await self._call("queue_status")
|
|
217
|
+
|
|
218
|
+
async def cancel(self, request_id: str) -> Any:
|
|
219
|
+
"""Cancel a queued request.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
request_id: Identifier of the request to cancel.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
The queue state the cancellation produced.
|
|
226
|
+
"""
|
|
227
|
+
return await self._call("cancel", {"request_id": request_id})
|
|
228
|
+
|
|
229
|
+
async def local_model_cache_preload(self, model_name: str) -> Any:
|
|
230
|
+
"""Prepare a model in the local disk cache.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
model_name: Model to preload.
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
The preload result.
|
|
237
|
+
"""
|
|
238
|
+
return await self._call("local_model_cache_preload", {"model_name": model_name})
|
|
239
|
+
|
|
240
|
+
async def local_model_cache_status(self, model_name: str) -> Any:
|
|
241
|
+
"""Report local disk-cache status for a model.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
model_name: Model to inspect.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
The cache status result.
|
|
248
|
+
"""
|
|
249
|
+
return await self._call("local_model_cache_status", {"model_name": model_name})
|
|
250
|
+
|
|
251
|
+
async def local_model_cache_delete(self, model_name: str) -> Any:
|
|
252
|
+
"""Remove a model from the tracked local disk cache.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
model_name: Model to remove.
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
The delete result.
|
|
259
|
+
"""
|
|
260
|
+
return await self._call("local_model_cache_delete", {"model_name": model_name})
|
|
261
|
+
|
|
262
|
+
async def local_model_load(self, model_name: str, *, allow_preload: bool = False) -> Any:
|
|
263
|
+
"""Load a model into memory.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
model_name: Model to load.
|
|
267
|
+
allow_preload: Whether loading may preload an uncached model.
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
The load result.
|
|
271
|
+
"""
|
|
272
|
+
return await self._call(
|
|
273
|
+
"local_model_load",
|
|
274
|
+
{"model_name": model_name, "allow_preload": allow_preload},
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
async def local_model_unload(self, model_name: str) -> Any:
|
|
278
|
+
"""Unload a model from memory.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
model_name: Model to unload.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
The unload result.
|
|
285
|
+
"""
|
|
286
|
+
return await self._call("local_model_unload", {"model_name": model_name})
|
|
287
|
+
|
|
288
|
+
async def local_model_reload(self, model_name: str) -> Any:
|
|
289
|
+
"""Re-probe a model's residency.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
model_name: Model to reload.
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
The reload result.
|
|
296
|
+
"""
|
|
297
|
+
return await self._call("local_model_reload", {"model_name": model_name})
|
|
298
|
+
|
|
299
|
+
async def local_lmcache_status(self) -> Any:
|
|
300
|
+
"""Report LMCache enablement, per-tier usage and hit accounting.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
The LMCache status.
|
|
304
|
+
"""
|
|
305
|
+
return await self._call("local_lmcache_status")
|
|
306
|
+
|
|
307
|
+
async def local_lmcache_purge(self, *, namespace: str | None = None, session: str | None = None) -> Any:
|
|
308
|
+
"""Remove cached LMCache artifacts globally or for one binding.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
namespace: Namespace binding to scope the purge to.
|
|
312
|
+
session: Session binding to scope the purge to.
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
The purge summary.
|
|
316
|
+
"""
|
|
317
|
+
params: dict[str, Any] = {}
|
|
318
|
+
if namespace is not None:
|
|
319
|
+
params["namespace"] = namespace
|
|
320
|
+
if session is not None:
|
|
321
|
+
params["session"] = session
|
|
322
|
+
return await self._call("local_lmcache_purge", params)
|
|
323
|
+
|
|
324
|
+
async def local_model_switch(self, model_name: str) -> Any:
|
|
325
|
+
"""Switch the resident model to another model.
|
|
326
|
+
|
|
327
|
+
This command is queued on the server, so the call returns only once the
|
|
328
|
+
switch has finished; the framework's queued-job facility does the
|
|
329
|
+
waiting.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
model_name: Model to switch to.
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
The switch result with its progress stages.
|
|
336
|
+
"""
|
|
337
|
+
return await self._call("local_model_switch", {"model_name": model_name}, queued=True)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lmrs-client
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Client library for the Local Model Runtime Service (LMRS)
|
|
5
|
+
Author-email: Vasiliy Zdanovskiy <vasilyvz@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: mcp-proxy-adapter>=8.10
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
lmrs_client/__init__.py,sha256=wbpNILp9VvS5PDUSJ4sv_duiHUZ9plobuER-xr2-PQg,321
|
|
2
|
+
lmrs_client/client.py,sha256=K9k0sEKMUUweQHgiox_IcSA3XUVvWh8qaJJejvP2auQ,11080
|
|
3
|
+
lmrs_client-0.1.4.dist-info/METADATA,sha256=dhHIuvZeLeqFeAGZQmzyd-AVuRJjQ0ZHEA133uKrE7M,292
|
|
4
|
+
lmrs_client-0.1.4.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
5
|
+
lmrs_client-0.1.4.dist-info/top_level.txt,sha256=royL3DdmV8FHbdCYRyjYGNlZ6fur82RLLxfji21DTWo,12
|
|
6
|
+
lmrs_client-0.1.4.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lmrs_client
|