@modular-prompt/driver 0.16.0 → 0.17.0
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.
- package/README.md +93 -10
- package/dist/cache-controller.d.ts +4 -0
- package/dist/cache-controller.d.ts.map +1 -1
- package/dist/driver-registry/config-based-factory.d.ts.map +1 -1
- package/dist/driver-registry/config-based-factory.js +6 -0
- package/dist/driver-registry/config-based-factory.js.map +1 -1
- package/dist/driver-registry/factory-helper.d.ts.map +1 -1
- package/dist/driver-registry/factory-helper.js +9 -2
- package/dist/driver-registry/factory-helper.js.map +1 -1
- package/dist/driver-registry/index.d.ts +1 -1
- package/dist/driver-registry/index.d.ts.map +1 -1
- package/dist/driver-registry/types.d.ts +15 -1
- package/dist/driver-registry/types.d.ts.map +1 -1
- package/dist/formatter/converter.d.ts.map +1 -1
- package/dist/formatter/converter.js +31 -2
- package/dist/formatter/converter.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/local-inference/adapters.d.ts +6 -0
- package/dist/local-inference/adapters.d.ts.map +1 -1
- package/dist/local-inference/driver.d.ts.map +1 -1
- package/dist/local-inference/driver.js +45 -24
- package/dist/local-inference/driver.js.map +1 -1
- package/dist/local-inference/process-client.d.ts +4 -2
- package/dist/local-inference/process-client.d.ts.map +1 -1
- package/dist/local-inference/process-client.js +24 -8
- package/dist/local-inference/process-client.js.map +1 -1
- package/dist/local-inference/process-communication.d.ts +9 -2
- package/dist/local-inference/process-communication.d.ts.map +1 -1
- package/dist/local-inference/process-communication.js +37 -5
- package/dist/local-inference/process-communication.js.map +1 -1
- package/dist/local-inference/protocol.d.ts +4 -0
- package/dist/local-inference/protocol.d.ts.map +1 -1
- package/dist/local-inference/request-queue.d.ts +1 -1
- package/dist/local-inference/request-queue.d.ts.map +1 -1
- package/dist/local-inference/request-queue.js +26 -7
- package/dist/local-inference/request-queue.js.map +1 -1
- package/dist/local-inference/stream-utils.d.ts +6 -0
- package/dist/local-inference/stream-utils.d.ts.map +1 -1
- package/dist/local-inference/stream-utils.js.map +1 -1
- package/dist/mlx-ml/mlx-cache-controller.d.ts +9 -0
- package/dist/mlx-ml/mlx-cache-controller.d.ts.map +1 -1
- package/dist/mlx-ml/mlx-cache-controller.js +158 -33
- package/dist/mlx-ml/mlx-cache-controller.js.map +1 -1
- package/dist/mlx-ml/mlx-cache-support.d.ts +2 -2
- package/dist/mlx-ml/mlx-cache-support.d.ts.map +1 -1
- package/dist/mlx-ml/mlx-cache-support.js +8 -3
- package/dist/mlx-ml/mlx-cache-support.js.map +1 -1
- package/dist/mlx-ml/mlx-driver.d.ts +0 -1
- package/dist/mlx-ml/mlx-driver.d.ts.map +1 -1
- package/dist/mlx-ml/mlx-driver.js +1 -8
- package/dist/mlx-ml/mlx-driver.js.map +1 -1
- package/dist/mlx-ml/process/index.d.ts +1 -1
- package/dist/mlx-ml/process/index.d.ts.map +1 -1
- package/dist/mlx-ml/process/index.js +2 -2
- package/dist/mlx-ml/process/index.js.map +1 -1
- package/dist/models-config/index.d.ts +1 -1
- package/dist/models-config/index.d.ts.map +1 -1
- package/dist/models-config/index.js +1 -1
- package/dist/models-config/index.js.map +1 -1
- package/dist/models-config/resolve.d.ts +9 -1
- package/dist/models-config/resolve.d.ts.map +1 -1
- package/dist/models-config/resolve.js +94 -2
- package/dist/models-config/resolve.js.map +1 -1
- package/dist/models-config/types.d.ts +3 -1
- package/dist/models-config/types.d.ts.map +1 -1
- package/dist/pytorch/process/index.d.ts +4 -2
- package/dist/pytorch/process/index.d.ts.map +1 -1
- package/dist/pytorch/process/index.js +24 -7
- package/dist/pytorch/process/index.js.map +1 -1
- package/dist/pytorch/pytorch-cache-controller.d.ts +84 -0
- package/dist/pytorch/pytorch-cache-controller.d.ts.map +1 -0
- package/dist/pytorch/pytorch-cache-controller.js +742 -0
- package/dist/pytorch/pytorch-cache-controller.js.map +1 -0
- package/dist/pytorch/pytorch-cache-support.d.ts +23 -0
- package/dist/pytorch/pytorch-cache-support.d.ts.map +1 -0
- package/dist/pytorch/pytorch-cache-support.js +47 -0
- package/dist/pytorch/pytorch-cache-support.js.map +1 -0
- package/dist/pytorch/pytorch-driver.d.ts +8 -1
- package/dist/pytorch/pytorch-driver.d.ts.map +1 -1
- package/dist/pytorch/pytorch-driver.js +40 -0
- package/dist/pytorch/pytorch-driver.js.map +1 -1
- package/dist/runtime/check.d.ts.map +1 -1
- package/dist/runtime/check.js +8 -6
- package/dist/runtime/check.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/manifest-core.d.mts +1 -0
- package/dist/runtime/manifest-core.mjs +1 -0
- package/dist/runtime/manifest-core.mjs.map +1 -1
- package/dist/runtime/manifest.d.ts +2 -0
- package/dist/runtime/manifest.d.ts.map +1 -1
- package/dist/runtime/manifest.js.map +1 -1
- package/dist/runtime/paths-core.d.mts +15 -1
- package/dist/runtime/paths-core.d.mts.map +1 -1
- package/dist/runtime/paths-core.mjs +50 -5
- package/dist/runtime/paths-core.mjs.map +1 -1
- package/dist/runtime/paths.d.ts +2 -2
- package/dist/runtime/paths.d.ts.map +1 -1
- package/dist/runtime/paths.js +2 -2
- package/dist/runtime/paths.js.map +1 -1
- package/dist/runtime/pytorch-template-core.d.mts +11 -0
- package/dist/runtime/pytorch-template-core.d.mts.map +1 -0
- package/dist/runtime/pytorch-template-core.mjs +54 -0
- package/dist/runtime/pytorch-template-core.mjs.map +1 -0
- package/dist/runtime/setup-commands-core.d.mts +3 -0
- package/dist/runtime/setup-commands-core.d.mts.map +1 -1
- package/dist/runtime/setup-commands-core.mjs +4 -0
- package/dist/runtime/setup-commands-core.mjs.map +1 -1
- package/dist/runtime/setup-commands.d.ts +1 -1
- package/dist/runtime/setup-commands.d.ts.map +1 -1
- package/dist/runtime/setup-commands.js +1 -1
- package/dist/runtime/setup-commands.js.map +1 -1
- package/docs/DRIVER_API.md +455 -0
- package/docs/LOCAL_MODEL_SETUP.md +765 -0
- package/docs/mlx-api-selection.md +301 -0
- package/package.json +9 -5
- package/scripts/runtime-cli.bin.test.ts +142 -0
- package/scripts/runtime-cli.js +305 -35
- package/scripts/runtime-cli.test.ts +163 -0
- package/src/mlx-ml/python/__main__.py +1 -1
- package/src/mlx-ml/python/backends/base.py +88 -18
- package/src/mlx-ml/python/backends/mlx_lm.py +28 -3
- package/src/mlx-ml/python/backends/mlx_vlm.py +679 -2
- package/src/mlx-ml/python/handlers/cache.py +4 -0
- package/src/mlx-ml/python/handlers/generate.py +33 -10
- package/src/mlx-ml/python/handlers/tokenize.py +1 -4
- package/src/mlx-ml/python/pyproject.toml +1 -1
- package/src/mlx-ml/python/server.py +2 -0
- package/src/mlx-ml/python/uv.lock +8 -8
- package/src/pytorch/templates/cpu-minimal/backends/base.py +139 -0
- package/src/pytorch/templates/cpu-minimal/backends/transformers_lm.py +1167 -0
- package/src/pytorch/{python → templates/cpu-minimal}/handlers/__init__.py +1 -0
- package/src/pytorch/templates/cpu-minimal/handlers/cache.py +88 -0
- package/src/pytorch/templates/cpu-minimal/handlers/generate.py +157 -0
- package/src/pytorch/{python → templates/cpu-minimal}/pyproject.toml +2 -2
- package/src/pytorch/{python → templates/cpu-minimal}/server.py +20 -2
- package/src/pytorch/templates/cpu-minimal/tests/test_cache_handler.py +284 -0
- package/src/pytorch/templates/cpu-minimal/tests/test_capabilities.py +14 -0
- package/src/pytorch/templates/cpu-minimal/tests/test_server.py +141 -0
- package/src/pytorch/templates/cpu-minimal/tests/test_transformers_errors.py +89 -0
- package/src/pytorch/templates/cpu-minimal/tests/test_transformers_lm_cache.py +554 -0
- package/src/pytorch/templates/cpu-minimal/utils/__init__.py +0 -0
- package/src/pytorch/{python → templates/cpu-minimal}/utils/token_utils.py +2 -2
- package/src/pytorch/templates/cpu-minimal/utils/transformers_errors.py +54 -0
- package/src/pytorch/{python → templates/cpu-minimal}/uv.lock +149 -109
- package/src/pytorch/templates/cuda/__main__.py +19 -0
- package/src/pytorch/templates/cuda/backends/__init__.py +3 -0
- package/src/pytorch/{python → templates/cuda}/backends/base.py +54 -6
- package/src/pytorch/templates/cuda/backends/transformers_lm.py +379 -0
- package/src/pytorch/templates/cuda/handlers/__init__.py +7 -0
- package/src/pytorch/templates/cuda/handlers/cache.py +93 -0
- package/src/pytorch/templates/cuda/handlers/cancel.py +53 -0
- package/src/pytorch/templates/cuda/handlers/capabilities.py +6 -0
- package/src/pytorch/templates/cuda/handlers/completion.py +15 -0
- package/src/pytorch/templates/cuda/handlers/format_test.py +70 -0
- package/src/pytorch/templates/cuda/handlers/generate.py +152 -0
- package/src/pytorch/templates/cuda/handlers/render.py +40 -0
- package/src/pytorch/templates/cuda/handlers/tokenize.py +63 -0
- package/src/pytorch/templates/cuda/pyproject.toml +37 -0
- package/src/pytorch/templates/cuda/server.py +158 -0
- package/src/pytorch/templates/cuda/tests/__init__.py +0 -0
- package/src/pytorch/templates/cuda/tests/test_cache_handler.py +207 -0
- package/src/pytorch/templates/cuda/tests/test_capabilities.py +14 -0
- package/src/pytorch/templates/cuda/tests/test_server.py +145 -0
- package/src/pytorch/templates/cuda/tests/test_transformers_errors.py +89 -0
- package/src/pytorch/templates/cuda/tests/test_transformers_lm_cache.py +288 -0
- package/src/pytorch/templates/cuda/utils/__init__.py +0 -0
- package/src/pytorch/templates/cuda/utils/chat_template_constraints.py +164 -0
- package/src/pytorch/templates/cuda/utils/prompt_builder.py +54 -0
- package/src/pytorch/templates/cuda/utils/template_render.py +80 -0
- package/src/pytorch/templates/cuda/utils/token_utils.py +376 -0
- package/src/pytorch/templates/cuda/utils/transformers_errors.py +54 -0
- package/src/pytorch/templates/cuda/uv.lock +734 -0
- package/src/pytorch/python/backends/transformers_lm.py +0 -127
- package/src/pytorch/python/handlers/generate.py +0 -68
- /package/src/pytorch/{python → templates/cpu-minimal}/__main__.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/backends/__init__.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/handlers/cancel.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/handlers/capabilities.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/handlers/completion.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/handlers/format_test.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/handlers/render.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/handlers/tokenize.py +0 -0
- /package/src/pytorch/{python/utils → templates/cpu-minimal/tests}/__init__.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/utils/chat_template_constraints.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/utils/prompt_builder.py +0 -0
- /package/src/pytorch/{python → templates/cpu-minimal}/utils/template_render.py +0 -0
|
@@ -18,6 +18,8 @@ def handle_cache_prefill(
|
|
|
18
18
|
prefix_hashes: list[str] | None = None,
|
|
19
19
|
tools: list | None = None,
|
|
20
20
|
reasoning_effort: str | None = None,
|
|
21
|
+
images: list | None = None,
|
|
22
|
+
max_image_size: int = 768,
|
|
21
23
|
) -> None:
|
|
22
24
|
tokenizer = backend.get_tokenizer()
|
|
23
25
|
|
|
@@ -74,6 +76,8 @@ def handle_cache_prefill(
|
|
|
74
76
|
trim_to_tokens=trim_to_tokens,
|
|
75
77
|
prefix_offsets=prefix_offsets,
|
|
76
78
|
prefix_hashes=prefix_hashes,
|
|
79
|
+
images=images,
|
|
80
|
+
max_image_size=max_image_size,
|
|
77
81
|
)
|
|
78
82
|
if prefix_offsets and prefix_hashes:
|
|
79
83
|
result["prefix_offsets"] = prefix_offsets
|
|
@@ -6,7 +6,6 @@ import re
|
|
|
6
6
|
import sys
|
|
7
7
|
|
|
8
8
|
from backends.base import ModelBackend
|
|
9
|
-
from mlx_lm.models.cache import trim_prompt_cache
|
|
10
9
|
from handlers.cancel import poll_cancel
|
|
11
10
|
|
|
12
11
|
|
|
@@ -29,6 +28,7 @@ def _stream_to_stdout(
|
|
|
29
28
|
images: list | None = None,
|
|
30
29
|
primer: str | None = None,
|
|
31
30
|
prompt_cache: list | None = None,
|
|
31
|
+
cache_loaded: bool | None = None,
|
|
32
32
|
) -> None:
|
|
33
33
|
if primer is not None:
|
|
34
34
|
print(primer, end="", flush=True)
|
|
@@ -46,6 +46,8 @@ def _stream_to_stdout(
|
|
|
46
46
|
meta["prompt_tokens"] = last_response.prompt_tokens
|
|
47
47
|
if hasattr(last_response, "generation_tokens"):
|
|
48
48
|
meta["generation_tokens"] = last_response.generation_tokens
|
|
49
|
+
if cache_loaded is not None:
|
|
50
|
+
meta["cache_loaded"] = cache_loaded
|
|
49
51
|
|
|
50
52
|
if meta:
|
|
51
53
|
print(f"\x1e__META__:{json.dumps(meta)}", end="\0", flush=True)
|
|
@@ -84,16 +86,22 @@ def handle_generate(
|
|
|
84
86
|
else:
|
|
85
87
|
sys.stderr.write(f"--- prompt\n{prompt}\n")
|
|
86
88
|
|
|
87
|
-
# VLM 経路では KV キャッシュを使わない(旧 chat ハンドラと同様)
|
|
88
89
|
prompt_cache = None
|
|
89
90
|
cache_tokens = 0
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
cache_loaded = None
|
|
92
|
+
if cache_path:
|
|
93
|
+
prompt_cache = backend.load_cache_from_file(
|
|
94
|
+
cache_path,
|
|
95
|
+
images=images,
|
|
96
|
+
max_image_size=max_image_size,
|
|
97
|
+
prompt=prompt,
|
|
98
|
+
)
|
|
99
|
+
cache_loaded = prompt_cache is not None
|
|
92
100
|
if prompt_cache is not None:
|
|
93
101
|
if cache_trim_tokens is not None:
|
|
94
102
|
current_offset = backend.get_cache_offset(prompt_cache)
|
|
95
103
|
if current_offset > cache_trim_tokens:
|
|
96
|
-
|
|
104
|
+
backend.trim_cache(prompt_cache, current_offset - cache_trim_tokens)
|
|
97
105
|
sys.stderr.write(
|
|
98
106
|
f"KV cache trimmed: {current_offset} → {cache_trim_tokens} tokens\n"
|
|
99
107
|
)
|
|
@@ -101,9 +109,21 @@ def handle_generate(
|
|
|
101
109
|
else:
|
|
102
110
|
cache_tokens = current_offset
|
|
103
111
|
else:
|
|
104
|
-
meta_count =
|
|
112
|
+
meta_count = (
|
|
113
|
+
_read_cache_token_count(cache_path)
|
|
114
|
+
if cache_path
|
|
115
|
+
else None
|
|
116
|
+
)
|
|
105
117
|
if meta_count is not None:
|
|
106
118
|
cache_tokens = meta_count
|
|
119
|
+
elif (
|
|
120
|
+
backend.model_kind == "vlm"
|
|
121
|
+
and cache_path is not None
|
|
122
|
+
and cache_path.startswith("mlx-vlm-memory://")
|
|
123
|
+
):
|
|
124
|
+
# Keep the Phase 1 in-process ref as a compatibility fallback.
|
|
125
|
+
# Persistent VLM refs always have the sidecar above.
|
|
126
|
+
cache_tokens = backend.get_cache_offset(prompt_cache)
|
|
107
127
|
else:
|
|
108
128
|
sys.stderr.write(
|
|
109
129
|
f"WARNING: Cache file exists but no .meta.json found at {cache_path}. "
|
|
@@ -111,6 +131,7 @@ def handle_generate(
|
|
|
111
131
|
)
|
|
112
132
|
prompt_cache = None
|
|
113
133
|
cache_tokens = 0
|
|
134
|
+
cache_loaded = False
|
|
114
135
|
if prompt_cache is not None:
|
|
115
136
|
sys.stderr.write(
|
|
116
137
|
f"KV cache loaded: {len(prompt_cache)} layers, {cache_tokens} cached tokens\n"
|
|
@@ -122,11 +143,11 @@ def handle_generate(
|
|
|
122
143
|
|
|
123
144
|
effective_prompt = prompt
|
|
124
145
|
if prompt_cache is not None and cache_tokens > 0 and isinstance(prompt, str):
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
full_tokens = backend.tokenize_prompt(
|
|
147
|
+
prompt,
|
|
148
|
+
images=images,
|
|
149
|
+
max_image_size=max_image_size,
|
|
128
150
|
)
|
|
129
|
-
full_tokens = tokenizer.encode(prompt, add_special_tokens=add_special)
|
|
130
151
|
|
|
131
152
|
if cache_tokens < len(full_tokens):
|
|
132
153
|
effective_prompt = full_tokens[cache_tokens:]
|
|
@@ -140,6 +161,7 @@ def handle_generate(
|
|
|
140
161
|
f"ignoring prefill state\n"
|
|
141
162
|
)
|
|
142
163
|
prompt_cache = None
|
|
164
|
+
cache_loaded = False
|
|
143
165
|
|
|
144
166
|
_stream_to_stdout(
|
|
145
167
|
backend,
|
|
@@ -148,4 +170,5 @@ def handle_generate(
|
|
|
148
170
|
images=images,
|
|
149
171
|
primer=primer,
|
|
150
172
|
prompt_cache=prompt_cache,
|
|
173
|
+
cache_loaded=cache_loaded,
|
|
151
174
|
)
|
|
@@ -50,10 +50,7 @@ def handle_tokenize(
|
|
|
50
50
|
prompt = generate_merged_prompt(messages, capabilities)
|
|
51
51
|
|
|
52
52
|
# トークン化
|
|
53
|
-
|
|
54
|
-
tokenizer.bos_token or ""
|
|
55
|
-
)
|
|
56
|
-
token_ids = tokenizer.encode(prompt, add_special_tokens=add_special)
|
|
53
|
+
token_ids = backend.tokenize_prompt(prompt)
|
|
57
54
|
|
|
58
55
|
result["token_ids"] = token_ids
|
|
59
56
|
result["token_count"] = len(token_ids)
|
|
@@ -10,7 +10,7 @@ dependencies = [
|
|
|
10
10
|
"mlx>=0.32.2; sys_platform == 'darwin'",
|
|
11
11
|
"mlx-lm==0.31.3; sys_platform == 'darwin'",
|
|
12
12
|
"mlx-optiq>=0.4.4; sys_platform == 'darwin'",
|
|
13
|
-
"mlx-vlm==0.
|
|
13
|
+
"mlx-vlm==0.7.0; sys_platform == 'darwin'",
|
|
14
14
|
"tokenizers==0.22.2",
|
|
15
15
|
"torch==2.9.1",
|
|
16
16
|
"torchvision==0.24.1",
|
|
@@ -100,6 +100,8 @@ class Server:
|
|
|
100
100
|
prefix_hashes=req.get('prefix_hashes'),
|
|
101
101
|
tools=req.get('tools'),
|
|
102
102
|
reasoning_effort=req.get('reasoning_effort'),
|
|
103
|
+
images=req.get('images'),
|
|
104
|
+
max_image_size=req.get('maxImageSize', 768),
|
|
103
105
|
)
|
|
104
106
|
|
|
105
107
|
elif method == 'render':
|
|
@@ -724,22 +724,21 @@ wheels = [
|
|
|
724
724
|
|
|
725
725
|
[[package]]
|
|
726
726
|
name = "mlx-audio"
|
|
727
|
-
version = "0.
|
|
727
|
+
version = "0.5.3"
|
|
728
728
|
source = { registry = "https://pypi.org/simple" }
|
|
729
729
|
dependencies = [
|
|
730
730
|
{ name = "huggingface-hub", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
731
731
|
{ name = "miniaudio", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
732
732
|
{ name = "mlx", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
733
|
-
{ name = "mlx-lm", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
734
733
|
{ name = "numpy", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
735
734
|
{ name = "scipy", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
736
735
|
{ name = "sounddevice", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
737
736
|
{ name = "tqdm", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
738
737
|
{ name = "transformers", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
739
738
|
]
|
|
740
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
739
|
+
sdist = { url = "https://files.pythonhosted.org/packages/60/e8/54d02c8bb50fc5b2cae0fbcb459acf78f1fbb316f20f758a8f56824aa407/mlx_audio-0.5.3.tar.gz", hash = "sha256:9e96f1ee68bc81e7ba74d85b8eab213384c8cd8c6f66ccd12034ded7cb5cd167", size = 1709447, upload-time = "2026-09-07T19:44:40.285Z" }
|
|
741
740
|
wheels = [
|
|
742
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
741
|
+
{ url = "https://files.pythonhosted.org/packages/84/c2/2876e6ff4811b1d6a43e1480947dd6580d02dba16f34724b2e3645090997/mlx_audio-0.5.3-py3-none-any.whl", hash = "sha256:8d920b2dcbcf37b5fd2bbb070e21a9a33442bf231a754e0d39387e65986bd830", size = 2057098, upload-time = "2026-09-07T19:44:38.581Z" },
|
|
743
742
|
]
|
|
744
743
|
|
|
745
744
|
[[package]]
|
|
@@ -773,7 +772,7 @@ requires-dist = [
|
|
|
773
772
|
{ name = "mlx", marker = "sys_platform == 'darwin'", specifier = ">=0.32.2" },
|
|
774
773
|
{ name = "mlx-lm", marker = "sys_platform == 'darwin'", specifier = "==0.31.3" },
|
|
775
774
|
{ name = "mlx-optiq", marker = "sys_platform == 'darwin'", specifier = ">=0.4.4" },
|
|
776
|
-
{ name = "mlx-vlm", marker = "sys_platform == 'darwin'", specifier = "==0.
|
|
775
|
+
{ name = "mlx-vlm", marker = "sys_platform == 'darwin'", specifier = "==0.7.0" },
|
|
777
776
|
{ name = "tokenizers", specifier = "==0.22.2" },
|
|
778
777
|
{ name = "torch", specifier = "==2.9.1" },
|
|
779
778
|
{ name = "torchvision", specifier = "==0.24.1" },
|
|
@@ -846,10 +845,11 @@ wheels = [
|
|
|
846
845
|
|
|
847
846
|
[[package]]
|
|
848
847
|
name = "mlx-vlm"
|
|
849
|
-
version = "0.
|
|
848
|
+
version = "0.7.0"
|
|
850
849
|
source = { registry = "https://pypi.org/simple" }
|
|
851
850
|
dependencies = [
|
|
852
851
|
{ name = "fastapi", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
852
|
+
{ name = "jinja2", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
853
853
|
{ name = "llguidance", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
854
854
|
{ name = "miniaudio", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
855
855
|
{ name = "mlx", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
@@ -866,9 +866,9 @@ dependencies = [
|
|
|
866
866
|
{ name = "uvicorn", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
867
867
|
{ name = "websockets", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
|
|
868
868
|
]
|
|
869
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
869
|
+
sdist = { url = "https://files.pythonhosted.org/packages/1e/9e/220a9427b1cf6f4ee381aa475fc47ecbe6d84f4177f0ac28176c3435fbdd/mlx_vlm-0.7.0.tar.gz", hash = "sha256:0bfc3ae1f82cb0a7866bf9f1257d672f6450c5fbd13f22b2d62fddb72b759379", size = 2208403, upload-time = "2026-09-07T15:25:14.497Z" }
|
|
870
870
|
wheels = [
|
|
871
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
871
|
+
{ url = "https://files.pythonhosted.org/packages/65/2c/3868b7ccb50c3cb975e7387de0b1e642b8896f2504a80d097f109d694eb4/mlx_vlm-0.7.0-py3-none-any.whl", hash = "sha256:5ea0c2b8182c055068cb0da59cb2503c238c428a07daaa0bebc246e8c666f4d3", size = 2787810, upload-time = "2026-09-07T15:25:12.683Z" },
|
|
872
872
|
]
|
|
873
873
|
|
|
874
874
|
[[package]]
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Iterator
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ModelBackend(ABC):
|
|
6
|
+
"""Abstract base class for model backends."""
|
|
7
|
+
|
|
8
|
+
@abstractmethod
|
|
9
|
+
def load(self, model_name: str) -> None:
|
|
10
|
+
"""Load the target model."""
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def get_tokenizer(self) -> Any:
|
|
15
|
+
"""Return the tokenizer or processor."""
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def stream_generate(
|
|
20
|
+
self, prompt: str | list[int], options: dict, images: list | None = None,
|
|
21
|
+
prompt_cache: Any | None = None,
|
|
22
|
+
) -> Iterator[Any]:
|
|
23
|
+
"""Stream generation results."""
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def supports_vision(self) -> bool:
|
|
28
|
+
"""Return whether image input is supported."""
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def model_kind(self) -> str:
|
|
34
|
+
"""Return "lm" or "vlm"."""
|
|
35
|
+
raise NotImplementedError
|
|
36
|
+
|
|
37
|
+
def load_drafter(self, drafter_model: str) -> None:
|
|
38
|
+
"""Load a drafter model for speculative decoding."""
|
|
39
|
+
raise NotImplementedError(
|
|
40
|
+
f"{type(self).__name__} does not support drafter models"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def has_drafter(self) -> bool:
|
|
44
|
+
"""Return whether a drafter model is loaded."""
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
def cache_prefill(
|
|
48
|
+
self,
|
|
49
|
+
cache_path: str,
|
|
50
|
+
prompt: str,
|
|
51
|
+
base_cache_path: str | None = None,
|
|
52
|
+
trim_to_tokens: int | None = None,
|
|
53
|
+
prefix_offsets: list[int] | None = None,
|
|
54
|
+
prefix_hashes: list[str] | None = None,
|
|
55
|
+
images: list | None = None,
|
|
56
|
+
max_image_size: int = 768,
|
|
57
|
+
) -> dict:
|
|
58
|
+
"""Build a KV cache from a prompt prefix."""
|
|
59
|
+
raise NotImplementedError(
|
|
60
|
+
f"{type(self).__name__} does not support prompt caching"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def consume_cache_write_tokens(self, cache_path: str) -> int:
|
|
64
|
+
"""Return and clear write usage pending for a cache reference."""
|
|
65
|
+
return 0
|
|
66
|
+
|
|
67
|
+
def trim_cache(self, prompt_cache: Any, tokens: int) -> Any:
|
|
68
|
+
"""Remove trailing tokens from a backend-owned prompt cache."""
|
|
69
|
+
raise NotImplementedError(
|
|
70
|
+
f"{type(self).__name__} does not support prompt cache trimming"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def tokenize_prompt(
|
|
74
|
+
self,
|
|
75
|
+
prompt: str,
|
|
76
|
+
images: list | None = None,
|
|
77
|
+
max_image_size: int = 768,
|
|
78
|
+
) -> list[int]:
|
|
79
|
+
"""Tokenize a rendered prompt using the backend's prompt rules."""
|
|
80
|
+
tokenizer = self.get_tokenizer()
|
|
81
|
+
bos_token = getattr(tokenizer, "bos_token", None)
|
|
82
|
+
add_special = bos_token is None or not prompt.startswith(bos_token or "")
|
|
83
|
+
token_ids = tokenizer.encode(prompt, add_special_tokens=add_special)
|
|
84
|
+
if hasattr(token_ids, "flatten"):
|
|
85
|
+
token_ids = token_ids.flatten().tolist()
|
|
86
|
+
return [int(token_id) for token_id in token_ids]
|
|
87
|
+
|
|
88
|
+
def load_cache_from_file(
|
|
89
|
+
self,
|
|
90
|
+
cache_path: str,
|
|
91
|
+
images: list | None = None,
|
|
92
|
+
max_image_size: int = 768,
|
|
93
|
+
prompt: str | list[int] | None = None,
|
|
94
|
+
prefix_token_count: int | None = None,
|
|
95
|
+
) -> Any | None:
|
|
96
|
+
"""Load a prompt cache, optionally validating only a prompt prefix."""
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
def get_cache_offset(self, prompt_cache: Any) -> int:
|
|
100
|
+
"""Get the number of tokens stored in a loaded prompt cache."""
|
|
101
|
+
if not prompt_cache:
|
|
102
|
+
return 0
|
|
103
|
+
|
|
104
|
+
get_seq_length = getattr(prompt_cache, "get_seq_length", None)
|
|
105
|
+
if callable(get_seq_length):
|
|
106
|
+
try:
|
|
107
|
+
return int(get_seq_length())
|
|
108
|
+
except Exception:
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
keys = getattr(prompt_cache, "keys", None)
|
|
112
|
+
if keys is not None:
|
|
113
|
+
try:
|
|
114
|
+
return int(keys.shape[-2])
|
|
115
|
+
except Exception:
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
layers = getattr(prompt_cache, "layers", None)
|
|
119
|
+
if layers:
|
|
120
|
+
return self.get_cache_offset(layers[0])
|
|
121
|
+
|
|
122
|
+
layer0 = prompt_cache[0]
|
|
123
|
+
if hasattr(layer0, 'offset'):
|
|
124
|
+
off = layer0.offset
|
|
125
|
+
return int(off.item() if hasattr(off, 'item') else off)
|
|
126
|
+
if hasattr(layer0, 'caches'):
|
|
127
|
+
for c in layer0.caches:
|
|
128
|
+
if hasattr(c, 'offset'):
|
|
129
|
+
off = c.offset
|
|
130
|
+
return int(off.item() if hasattr(off, 'item') else off)
|
|
131
|
+
try:
|
|
132
|
+
key = layer0[0] if isinstance(layer0, (list, tuple)) else layer0
|
|
133
|
+
shape = key.shape
|
|
134
|
+
return int(shape[-2] if len(shape) >= 2 else shape[0])
|
|
135
|
+
except Exception:
|
|
136
|
+
pass
|
|
137
|
+
if hasattr(layer0, 'keys') and layer0.keys is not None:
|
|
138
|
+
return int(layer0.keys.shape[-2])
|
|
139
|
+
return 0
|