@modular-prompt/driver 0.15.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.
Files changed (198) hide show
  1. package/README.md +124 -9
  2. package/dist/cache-controller.d.ts +4 -0
  3. package/dist/cache-controller.d.ts.map +1 -1
  4. package/dist/driver-registry/config-based-factory.d.ts.map +1 -1
  5. package/dist/driver-registry/config-based-factory.js +10 -3
  6. package/dist/driver-registry/config-based-factory.js.map +1 -1
  7. package/dist/driver-registry/factory-helper.d.ts.map +1 -1
  8. package/dist/driver-registry/factory-helper.js +10 -2
  9. package/dist/driver-registry/factory-helper.js.map +1 -1
  10. package/dist/driver-registry/index.d.ts +1 -1
  11. package/dist/driver-registry/index.d.ts.map +1 -1
  12. package/dist/driver-registry/types.d.ts +18 -1
  13. package/dist/driver-registry/types.d.ts.map +1 -1
  14. package/dist/formatter/converter.d.ts.map +1 -1
  15. package/dist/formatter/converter.js +31 -2
  16. package/dist/formatter/converter.js.map +1 -1
  17. package/dist/index.d.ts +5 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +5 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/local-inference/adapters.d.ts +6 -0
  22. package/dist/local-inference/adapters.d.ts.map +1 -1
  23. package/dist/local-inference/driver.d.ts.map +1 -1
  24. package/dist/local-inference/driver.js +45 -24
  25. package/dist/local-inference/driver.js.map +1 -1
  26. package/dist/local-inference/process-client.d.ts +4 -2
  27. package/dist/local-inference/process-client.d.ts.map +1 -1
  28. package/dist/local-inference/process-client.js +24 -8
  29. package/dist/local-inference/process-client.js.map +1 -1
  30. package/dist/local-inference/process-communication.d.ts +9 -2
  31. package/dist/local-inference/process-communication.d.ts.map +1 -1
  32. package/dist/local-inference/process-communication.js +37 -5
  33. package/dist/local-inference/process-communication.js.map +1 -1
  34. package/dist/local-inference/protocol.d.ts +4 -0
  35. package/dist/local-inference/protocol.d.ts.map +1 -1
  36. package/dist/local-inference/request-queue.d.ts +1 -1
  37. package/dist/local-inference/request-queue.d.ts.map +1 -1
  38. package/dist/local-inference/request-queue.js +26 -7
  39. package/dist/local-inference/request-queue.js.map +1 -1
  40. package/dist/local-inference/stream-utils.d.ts +6 -0
  41. package/dist/local-inference/stream-utils.d.ts.map +1 -1
  42. package/dist/local-inference/stream-utils.js.map +1 -1
  43. package/dist/mlx-ml/mlx-cache-controller.d.ts +9 -0
  44. package/dist/mlx-ml/mlx-cache-controller.d.ts.map +1 -1
  45. package/dist/mlx-ml/mlx-cache-controller.js +158 -32
  46. package/dist/mlx-ml/mlx-cache-controller.js.map +1 -1
  47. package/dist/mlx-ml/mlx-cache-support.d.ts +2 -2
  48. package/dist/mlx-ml/mlx-cache-support.d.ts.map +1 -1
  49. package/dist/mlx-ml/mlx-cache-support.js +8 -3
  50. package/dist/mlx-ml/mlx-cache-support.js.map +1 -1
  51. package/dist/mlx-ml/mlx-driver.d.ts +0 -1
  52. package/dist/mlx-ml/mlx-driver.d.ts.map +1 -1
  53. package/dist/mlx-ml/mlx-driver.js +1 -8
  54. package/dist/mlx-ml/mlx-driver.js.map +1 -1
  55. package/dist/mlx-ml/process/index.d.ts +1 -1
  56. package/dist/mlx-ml/process/index.d.ts.map +1 -1
  57. package/dist/mlx-ml/process/index.js +2 -2
  58. package/dist/mlx-ml/process/index.js.map +1 -1
  59. package/dist/models-config/index.d.ts +2 -2
  60. package/dist/models-config/index.d.ts.map +1 -1
  61. package/dist/models-config/index.js +2 -2
  62. package/dist/models-config/index.js.map +1 -1
  63. package/dist/models-config/paths.d.ts +8 -0
  64. package/dist/models-config/paths.d.ts.map +1 -1
  65. package/dist/models-config/paths.js +16 -1
  66. package/dist/models-config/paths.js.map +1 -1
  67. package/dist/models-config/resolve.d.ts +10 -2
  68. package/dist/models-config/resolve.d.ts.map +1 -1
  69. package/dist/models-config/resolve.js +119 -6
  70. package/dist/models-config/resolve.js.map +1 -1
  71. package/dist/models-config/types.d.ts +5 -1
  72. package/dist/models-config/types.d.ts.map +1 -1
  73. package/dist/pytorch/process/index.d.ts +4 -2
  74. package/dist/pytorch/process/index.d.ts.map +1 -1
  75. package/dist/pytorch/process/index.js +24 -7
  76. package/dist/pytorch/process/index.js.map +1 -1
  77. package/dist/pytorch/pytorch-cache-controller.d.ts +84 -0
  78. package/dist/pytorch/pytorch-cache-controller.d.ts.map +1 -0
  79. package/dist/pytorch/pytorch-cache-controller.js +742 -0
  80. package/dist/pytorch/pytorch-cache-controller.js.map +1 -0
  81. package/dist/pytorch/pytorch-cache-support.d.ts +23 -0
  82. package/dist/pytorch/pytorch-cache-support.d.ts.map +1 -0
  83. package/dist/pytorch/pytorch-cache-support.js +47 -0
  84. package/dist/pytorch/pytorch-cache-support.js.map +1 -0
  85. package/dist/pytorch/pytorch-driver.d.ts +8 -1
  86. package/dist/pytorch/pytorch-driver.d.ts.map +1 -1
  87. package/dist/pytorch/pytorch-driver.js +40 -0
  88. package/dist/pytorch/pytorch-driver.js.map +1 -1
  89. package/dist/runtime/check.d.ts.map +1 -1
  90. package/dist/runtime/check.js +9 -6
  91. package/dist/runtime/check.js.map +1 -1
  92. package/dist/runtime/index.d.ts +2 -1
  93. package/dist/runtime/index.d.ts.map +1 -1
  94. package/dist/runtime/index.js +2 -1
  95. package/dist/runtime/index.js.map +1 -1
  96. package/dist/runtime/manifest-core.d.mts +1 -0
  97. package/dist/runtime/manifest-core.mjs +1 -0
  98. package/dist/runtime/manifest-core.mjs.map +1 -1
  99. package/dist/runtime/manifest.d.ts +2 -0
  100. package/dist/runtime/manifest.d.ts.map +1 -1
  101. package/dist/runtime/manifest.js.map +1 -1
  102. package/dist/runtime/paths-core.d.mts +15 -1
  103. package/dist/runtime/paths-core.d.mts.map +1 -1
  104. package/dist/runtime/paths-core.mjs +50 -5
  105. package/dist/runtime/paths-core.mjs.map +1 -1
  106. package/dist/runtime/paths.d.ts +2 -2
  107. package/dist/runtime/paths.d.ts.map +1 -1
  108. package/dist/runtime/paths.js +2 -2
  109. package/dist/runtime/paths.js.map +1 -1
  110. package/dist/runtime/pytorch-template-core.d.mts +11 -0
  111. package/dist/runtime/pytorch-template-core.d.mts.map +1 -0
  112. package/dist/runtime/pytorch-template-core.mjs +54 -0
  113. package/dist/runtime/pytorch-template-core.mjs.map +1 -0
  114. package/dist/runtime/setup-commands-core.d.mts +16 -0
  115. package/dist/runtime/setup-commands-core.d.mts.map +1 -0
  116. package/dist/runtime/setup-commands-core.mjs +18 -0
  117. package/dist/runtime/setup-commands-core.mjs.map +1 -0
  118. package/dist/runtime/setup-commands.d.ts +2 -0
  119. package/dist/runtime/setup-commands.d.ts.map +1 -0
  120. package/dist/runtime/setup-commands.js +2 -0
  121. package/dist/runtime/setup-commands.js.map +1 -0
  122. package/docs/DRIVER_API.md +455 -0
  123. package/docs/LOCAL_MODEL_SETUP.md +765 -0
  124. package/docs/mlx-api-selection.md +301 -0
  125. package/package.json +12 -5
  126. package/scripts/download-model.js +3 -2
  127. package/scripts/runtime-cli.bin.test.ts +142 -0
  128. package/scripts/runtime-cli.js +322 -47
  129. package/scripts/runtime-cli.test.ts +163 -0
  130. package/src/mlx-ml/python/__main__.py +1 -1
  131. package/src/mlx-ml/python/backends/base.py +88 -18
  132. package/src/mlx-ml/python/backends/cache_archive.py +41 -0
  133. package/src/mlx-ml/python/backends/mlx_lm.py +45 -4
  134. package/src/mlx-ml/python/backends/mlx_vlm.py +679 -2
  135. package/src/mlx-ml/python/handlers/cache.py +4 -0
  136. package/src/mlx-ml/python/handlers/generate.py +33 -10
  137. package/src/mlx-ml/python/handlers/tokenize.py +1 -4
  138. package/src/mlx-ml/python/pyproject.toml +9 -3
  139. package/src/mlx-ml/python/server.py +2 -0
  140. package/src/mlx-ml/python/uv.lock +193 -433
  141. package/src/pytorch/templates/cpu-minimal/backends/base.py +139 -0
  142. package/src/pytorch/templates/cpu-minimal/backends/transformers_lm.py +1167 -0
  143. package/src/pytorch/{python → templates/cpu-minimal}/handlers/__init__.py +1 -0
  144. package/src/pytorch/templates/cpu-minimal/handlers/cache.py +88 -0
  145. package/src/pytorch/templates/cpu-minimal/handlers/generate.py +157 -0
  146. package/src/pytorch/{python → templates/cpu-minimal}/pyproject.toml +2 -2
  147. package/src/pytorch/{python → templates/cpu-minimal}/server.py +20 -2
  148. package/src/pytorch/templates/cpu-minimal/tests/test_cache_handler.py +284 -0
  149. package/src/pytorch/templates/cpu-minimal/tests/test_capabilities.py +14 -0
  150. package/src/pytorch/templates/cpu-minimal/tests/test_server.py +141 -0
  151. package/src/pytorch/templates/cpu-minimal/tests/test_transformers_errors.py +89 -0
  152. package/src/pytorch/templates/cpu-minimal/tests/test_transformers_lm_cache.py +554 -0
  153. package/src/pytorch/templates/cpu-minimal/utils/__init__.py +0 -0
  154. package/src/pytorch/{python → templates/cpu-minimal}/utils/token_utils.py +2 -2
  155. package/src/pytorch/templates/cpu-minimal/utils/transformers_errors.py +54 -0
  156. package/src/pytorch/{python → templates/cpu-minimal}/uv.lock +149 -109
  157. package/src/pytorch/templates/cuda/__main__.py +19 -0
  158. package/src/pytorch/templates/cuda/backends/__init__.py +3 -0
  159. package/src/pytorch/{python → templates/cuda}/backends/base.py +54 -6
  160. package/src/pytorch/templates/cuda/backends/transformers_lm.py +379 -0
  161. package/src/pytorch/templates/cuda/handlers/__init__.py +7 -0
  162. package/src/pytorch/templates/cuda/handlers/cache.py +93 -0
  163. package/src/pytorch/templates/cuda/handlers/cancel.py +53 -0
  164. package/src/pytorch/templates/cuda/handlers/capabilities.py +6 -0
  165. package/src/pytorch/templates/cuda/handlers/completion.py +15 -0
  166. package/src/pytorch/templates/cuda/handlers/format_test.py +70 -0
  167. package/src/pytorch/templates/cuda/handlers/generate.py +152 -0
  168. package/src/pytorch/templates/cuda/handlers/render.py +40 -0
  169. package/src/pytorch/templates/cuda/handlers/tokenize.py +63 -0
  170. package/src/pytorch/templates/cuda/pyproject.toml +37 -0
  171. package/src/pytorch/templates/cuda/server.py +158 -0
  172. package/src/pytorch/templates/cuda/tests/__init__.py +0 -0
  173. package/src/pytorch/templates/cuda/tests/test_cache_handler.py +207 -0
  174. package/src/pytorch/templates/cuda/tests/test_capabilities.py +14 -0
  175. package/src/pytorch/templates/cuda/tests/test_server.py +145 -0
  176. package/src/pytorch/templates/cuda/tests/test_transformers_errors.py +89 -0
  177. package/src/pytorch/templates/cuda/tests/test_transformers_lm_cache.py +288 -0
  178. package/src/pytorch/templates/cuda/utils/__init__.py +0 -0
  179. package/src/pytorch/templates/cuda/utils/chat_template_constraints.py +164 -0
  180. package/src/pytorch/templates/cuda/utils/prompt_builder.py +54 -0
  181. package/src/pytorch/templates/cuda/utils/template_render.py +80 -0
  182. package/src/pytorch/templates/cuda/utils/token_utils.py +376 -0
  183. package/src/pytorch/templates/cuda/utils/transformers_errors.py +54 -0
  184. package/src/pytorch/templates/cuda/uv.lock +734 -0
  185. package/src/pytorch/python/backends/transformers_lm.py +0 -127
  186. package/src/pytorch/python/handlers/generate.py +0 -68
  187. /package/src/pytorch/{python → templates/cpu-minimal}/__main__.py +0 -0
  188. /package/src/pytorch/{python → templates/cpu-minimal}/backends/__init__.py +0 -0
  189. /package/src/pytorch/{python → templates/cpu-minimal}/handlers/cancel.py +0 -0
  190. /package/src/pytorch/{python → templates/cpu-minimal}/handlers/capabilities.py +0 -0
  191. /package/src/pytorch/{python → templates/cpu-minimal}/handlers/completion.py +0 -0
  192. /package/src/pytorch/{python → templates/cpu-minimal}/handlers/format_test.py +0 -0
  193. /package/src/pytorch/{python → templates/cpu-minimal}/handlers/render.py +0 -0
  194. /package/src/pytorch/{python → templates/cpu-minimal}/handlers/tokenize.py +0 -0
  195. /package/src/pytorch/{python/utils → templates/cpu-minimal/tests}/__init__.py +0 -0
  196. /package/src/pytorch/{python → templates/cpu-minimal}/utils/chat_template_constraints.py +0 -0
  197. /package/src/pytorch/{python → templates/cpu-minimal}/utils/prompt_builder.py +0 -0
  198. /package/src/pytorch/{python → templates/cpu-minimal}/utils/template_render.py +0 -0
@@ -0,0 +1,141 @@
1
+ import json
2
+ from types import SimpleNamespace
3
+ from unittest.mock import MagicMock, patch
4
+
5
+
6
+ class _Tokenizer:
7
+ bos_token = "<bos>"
8
+ chat_template = "template"
9
+
10
+ def apply_chat_template(self, messages, **kwargs):
11
+ del messages, kwargs
12
+ return "prefix"
13
+
14
+
15
+ class _Backend:
16
+ model_kind = "lm"
17
+
18
+ def __init__(self):
19
+ self.tokenizer = _Tokenizer()
20
+ self.cache = None
21
+ self.generate_prompt = None
22
+ self.pending_cache_write_tokens = 0
23
+
24
+ def get_tokenizer(self):
25
+ return self.tokenizer
26
+
27
+ def cache_prefill(self, cache_path, prompt, **kwargs):
28
+ del prompt, kwargs
29
+ self.cache = object()
30
+ self.pending_cache_write_tokens = 2
31
+ return {
32
+ "cache_path": cache_path,
33
+ "token_count": 2,
34
+ "cache_write_tokens": 2,
35
+ }
36
+
37
+ def load_cache_from_file(self, cache_path, **kwargs):
38
+ del kwargs
39
+ return self.cache if cache_path == "memory://prefix" else None
40
+
41
+ def get_cache_offset(self, prompt_cache):
42
+ return 2 if prompt_cache is self.cache else 0
43
+
44
+ def consume_cache_write_tokens(self, cache_path):
45
+ del cache_path
46
+ result = self.pending_cache_write_tokens
47
+ self.pending_cache_write_tokens = 0
48
+ return result
49
+
50
+ def tokenize_prompt(self, prompt):
51
+ assert prompt == "prefix suffix"
52
+ return [1, 2, 3]
53
+
54
+ def stream_generate(self, prompt, options, images=None, prompt_cache=None):
55
+ del options, images
56
+ self.generate_prompt = prompt
57
+ assert prompt_cache is self.cache
58
+ yield SimpleNamespace(
59
+ text="ok",
60
+ prompt_tokens=3,
61
+ generation_tokens=1,
62
+ cache_read_tokens=2,
63
+ )
64
+
65
+
66
+ def _make_server():
67
+ from server import Server
68
+
69
+ backend = MagicMock()
70
+ return Server(backend, {"methods": ["capabilities"], "model_kind": "lm"})
71
+
72
+
73
+ def test_cache_prefill_dispatches_to_handler(capsys):
74
+ server = _make_server()
75
+
76
+ with patch("server.handle_cache_prefill") as mock_prefill:
77
+ server._dispatch(
78
+ {
79
+ "method": "cache_prefill",
80
+ "cache_path": "memory://prefix",
81
+ "messages": [{"role": "user", "content": "hello"}],
82
+ }
83
+ )
84
+
85
+ mock_prefill.assert_called_once()
86
+ assert mock_prefill.call_args.args[2:] == (
87
+ "memory://prefix",
88
+ [{"role": "user", "content": "hello"}],
89
+ )
90
+ assert capsys.readouterr().out == ""
91
+
92
+
93
+ def test_cache_prefill_requires_path_and_messages(capsys):
94
+ server = _make_server()
95
+
96
+ server._dispatch({"method": "cache_prefill"})
97
+
98
+ assert capsys.readouterr().out.endswith("\0")
99
+
100
+
101
+ def test_cache_prefill_then_generate_with_cache_via_server(capsys):
102
+ from server import Server
103
+
104
+ backend = _Backend()
105
+ server = Server(backend, {"methods": ["cache_prefill"], "model_kind": "lm"})
106
+
107
+ server._dispatch(
108
+ {
109
+ "method": "cache_prefill",
110
+ "cache_path": "memory://prefix",
111
+ "messages": [{"role": "user", "content": "hello"}],
112
+ }
113
+ )
114
+ prefill_output = capsys.readouterr().out
115
+ assert json.loads(prefill_output.split("\0", 1)[0]) == {
116
+ "cache_path": "memory://prefix",
117
+ "token_count": 2,
118
+ "cache_write_tokens": 2,
119
+ }
120
+
121
+ server._dispatch(
122
+ {
123
+ "method": "generate",
124
+ "prompt": "prefix suffix",
125
+ "options": {"max_tokens": 1},
126
+ "cache_path": "memory://prefix",
127
+ }
128
+ )
129
+ generate_output = capsys.readouterr().out
130
+ assert generate_output.startswith("ok")
131
+ meta = json.loads(
132
+ generate_output.split("\x1e__META__:", 1)[1].split("\0", 1)[0]
133
+ )
134
+ assert meta == {
135
+ "prompt_tokens": 3,
136
+ "generation_tokens": 1,
137
+ "cache_read_tokens": 2,
138
+ "cache_write_tokens": 2,
139
+ "cache_loaded": True,
140
+ }
141
+ assert backend.generate_prompt == [3]
@@ -0,0 +1,89 @@
1
+ from types import SimpleNamespace
2
+
3
+ import pytest
4
+
5
+ from utils.transformers_errors import (
6
+ MIN_TRANSFORMERS_VERSION,
7
+ extract_unsupported_model_type,
8
+ unsupported_model_type_error,
9
+ )
10
+
11
+
12
+ def test_extracts_model_type_from_transformers_value_error():
13
+ error = ValueError(
14
+ "The checkpoint has model type `qwen3_5` but Transformers does not "
15
+ "recognize this architecture."
16
+ )
17
+
18
+ assert extract_unsupported_model_type(error) == "qwen3_5"
19
+
20
+
21
+ def test_extracts_model_type_from_older_registry_key_error():
22
+ assert extract_unsupported_model_type(KeyError("qwen3_5")) == "qwen3_5"
23
+
24
+
25
+ def test_leaves_unrelated_errors_unchanged():
26
+ assert extract_unsupported_model_type(ValueError("invalid weights")) is None
27
+ assert extract_unsupported_model_type(KeyError("model_type")) is None
28
+
29
+
30
+ def test_error_includes_runtime_requirement_and_setup_guidance():
31
+ error = unsupported_model_type_error("Qwen/Qwen3.5-0.8B", "qwen3_5", "4.57.6")
32
+ message = str(error)
33
+
34
+ assert "qwen3_5" in message
35
+ assert "transformers 4.57.6" in message
36
+ assert f"transformers>={MIN_TRANSFORMERS_VERSION}" in message
37
+ assert "setup-pytorch" in message
38
+ assert "modular-prompt-runtime sync pytorch" in message
39
+
40
+
41
+ def test_backend_wraps_unknown_architecture_error(monkeypatch):
42
+ pytest.importorskip("torch")
43
+ import backends.transformers_lm as backend_module
44
+
45
+ tokenizer = SimpleNamespace(pad_token=None, eos_token="<eos>")
46
+ backend = backend_module.TransformersLmBackend(device="cpu")
47
+
48
+ def load_tokenizer(*args, **kwargs):
49
+ return tokenizer
50
+
51
+ def load_model(*args, **kwargs):
52
+ raise ValueError(
53
+ "The checkpoint has model type `qwen3_5` but Transformers does not "
54
+ "recognize this architecture."
55
+ )
56
+
57
+ monkeypatch.setattr(backend_module.AutoTokenizer, "from_pretrained", load_tokenizer)
58
+ monkeypatch.setattr(
59
+ backend_module.AutoModelForCausalLM,
60
+ "from_pretrained",
61
+ load_model,
62
+ )
63
+
64
+ with pytest.raises(RuntimeError, match="qwen3_5") as raised:
65
+ backend.load("Qwen/Qwen3.5-0.8B")
66
+
67
+ assert f"transformers {backend_module.transformers.__version__}" in str(raised.value)
68
+ assert "transformers>=5.14.0" in str(raised.value)
69
+
70
+
71
+ def test_backend_wraps_unknown_architecture_error_from_tokenizer(monkeypatch):
72
+ pytest.importorskip("torch")
73
+ import backends.transformers_lm as backend_module
74
+
75
+ backend = backend_module.TransformersLmBackend(device="cpu")
76
+
77
+ def load_tokenizer(*args, **kwargs):
78
+ raise ValueError(
79
+ "The checkpoint has model type `qwen3_5` but Transformers does not "
80
+ "recognize this architecture."
81
+ )
82
+
83
+ monkeypatch.setattr(backend_module.AutoTokenizer, "from_pretrained", load_tokenizer)
84
+
85
+ with pytest.raises(RuntimeError, match="qwen3_5") as raised:
86
+ backend.load("Qwen/Qwen3.5-0.8B")
87
+
88
+ assert f"transformers {backend_module.transformers.__version__}" in str(raised.value)
89
+ assert "transformers>=5.14.0" in str(raised.value)