@modular-prompt/driver 0.13.5 → 0.15.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 (213) hide show
  1. package/README.md +117 -4
  2. package/dist/driver-registry/ai-service.d.ts +23 -1
  3. package/dist/driver-registry/ai-service.d.ts.map +1 -1
  4. package/dist/driver-registry/ai-service.js +44 -10
  5. package/dist/driver-registry/ai-service.js.map +1 -1
  6. package/dist/driver-registry/config-based-factory.d.ts.map +1 -1
  7. package/dist/driver-registry/config-based-factory.js +16 -0
  8. package/dist/driver-registry/config-based-factory.js.map +1 -1
  9. package/dist/driver-registry/factory-helper.d.ts +2 -0
  10. package/dist/driver-registry/factory-helper.d.ts.map +1 -1
  11. package/dist/driver-registry/factory-helper.js +21 -3
  12. package/dist/driver-registry/factory-helper.js.map +1 -1
  13. package/dist/driver-registry/index.d.ts +2 -2
  14. package/dist/driver-registry/index.d.ts.map +1 -1
  15. package/dist/driver-registry/index.js +1 -1
  16. package/dist/driver-registry/index.js.map +1 -1
  17. package/dist/driver-registry/registry.d.ts.map +1 -1
  18. package/dist/driver-registry/registry.js +3 -1
  19. package/dist/driver-registry/registry.js.map +1 -1
  20. package/dist/driver-registry/types.d.ts +8 -2
  21. package/dist/driver-registry/types.d.ts.map +1 -1
  22. package/dist/index.d.ts +11 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +11 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/local-inference/adapters.d.ts +66 -0
  27. package/dist/local-inference/adapters.d.ts.map +1 -0
  28. package/dist/local-inference/adapters.js +2 -0
  29. package/dist/local-inference/adapters.js.map +1 -0
  30. package/dist/local-inference/driver.d.ts +51 -0
  31. package/dist/local-inference/driver.d.ts.map +1 -0
  32. package/dist/local-inference/driver.js +309 -0
  33. package/dist/local-inference/driver.js.map +1 -0
  34. package/dist/local-inference/index.d.ts +22 -0
  35. package/dist/local-inference/index.d.ts.map +1 -0
  36. package/dist/local-inference/index.js +17 -0
  37. package/dist/local-inference/index.js.map +1 -0
  38. package/dist/local-inference/process-client.d.ts +50 -0
  39. package/dist/local-inference/process-client.d.ts.map +1 -0
  40. package/dist/local-inference/process-client.js +92 -0
  41. package/dist/local-inference/process-client.js.map +1 -0
  42. package/dist/local-inference/process-communication.d.ts +41 -0
  43. package/dist/local-inference/process-communication.d.ts.map +1 -0
  44. package/dist/{mlx-ml/process → local-inference}/process-communication.js +40 -47
  45. package/dist/local-inference/process-communication.js.map +1 -0
  46. package/dist/local-inference/process-port.d.ts +12 -0
  47. package/dist/local-inference/process-port.d.ts.map +1 -0
  48. package/dist/local-inference/process-port.js +2 -0
  49. package/dist/local-inference/process-port.js.map +1 -0
  50. package/dist/local-inference/prompt-utils.d.ts +6 -0
  51. package/dist/local-inference/prompt-utils.d.ts.map +1 -0
  52. package/dist/local-inference/prompt-utils.js +17 -0
  53. package/dist/local-inference/prompt-utils.js.map +1 -0
  54. package/dist/local-inference/protocol.d.ts +192 -0
  55. package/dist/local-inference/protocol.d.ts.map +1 -0
  56. package/dist/local-inference/protocol.js +2 -0
  57. package/dist/local-inference/protocol.js.map +1 -0
  58. package/dist/local-inference/queue-types.d.ts +54 -0
  59. package/dist/local-inference/queue-types.d.ts.map +1 -0
  60. package/dist/local-inference/queue-types.js +2 -0
  61. package/dist/local-inference/queue-types.js.map +1 -0
  62. package/dist/local-inference/request-queue.d.ts +36 -0
  63. package/dist/local-inference/request-queue.d.ts.map +1 -0
  64. package/dist/{mlx-ml/process/queue.js → local-inference/request-queue.js} +89 -56
  65. package/dist/local-inference/request-queue.js.map +1 -0
  66. package/dist/local-inference/stream-utils.d.ts +19 -0
  67. package/dist/local-inference/stream-utils.d.ts.map +1 -0
  68. package/dist/local-inference/stream-utils.js +76 -0
  69. package/dist/local-inference/stream-utils.js.map +1 -0
  70. package/dist/mlx-ml/mlx-cache-support.d.ts +23 -0
  71. package/dist/mlx-ml/mlx-cache-support.d.ts.map +1 -0
  72. package/dist/mlx-ml/mlx-cache-support.js +45 -0
  73. package/dist/mlx-ml/mlx-cache-support.js.map +1 -0
  74. package/dist/mlx-ml/mlx-driver.d.ts +20 -59
  75. package/dist/mlx-ml/mlx-driver.d.ts.map +1 -1
  76. package/dist/mlx-ml/mlx-driver.js +86 -415
  77. package/dist/mlx-ml/mlx-driver.js.map +1 -1
  78. package/dist/mlx-ml/mlx-local-inference-adapters.d.ts +3 -0
  79. package/dist/mlx-ml/mlx-local-inference-adapters.d.ts.map +1 -0
  80. package/dist/mlx-ml/mlx-local-inference-adapters.js +19 -0
  81. package/dist/mlx-ml/mlx-local-inference-adapters.js.map +1 -0
  82. package/dist/mlx-ml/mlx-options.d.ts +19 -0
  83. package/dist/mlx-ml/mlx-options.d.ts.map +1 -0
  84. package/dist/mlx-ml/mlx-options.js +30 -0
  85. package/dist/mlx-ml/mlx-options.js.map +1 -0
  86. package/dist/mlx-ml/process/index.d.ts +11 -8
  87. package/dist/mlx-ml/process/index.d.ts.map +1 -1
  88. package/dist/mlx-ml/process/index.js +75 -52
  89. package/dist/mlx-ml/process/index.js.map +1 -1
  90. package/dist/mlx-ml/process/model-specific.d.ts +2 -1
  91. package/dist/mlx-ml/process/model-specific.d.ts.map +1 -1
  92. package/dist/mlx-ml/process/model-specific.js.map +1 -1
  93. package/dist/mlx-ml/process/prompt-builder.d.ts +11 -0
  94. package/dist/mlx-ml/process/prompt-builder.d.ts.map +1 -0
  95. package/dist/mlx-ml/process/prompt-builder.js +51 -0
  96. package/dist/mlx-ml/process/prompt-builder.js.map +1 -0
  97. package/dist/mlx-ml/process/types.d.ts +15 -183
  98. package/dist/mlx-ml/process/types.d.ts.map +1 -1
  99. package/dist/mlx-ml/tool-call-parser/tool-formatter.js +2 -2
  100. package/dist/mlx-ml/tool-call-parser/tool-formatter.js.map +1 -1
  101. package/dist/mlx-ml/types.d.ts +2 -45
  102. package/dist/mlx-ml/types.d.ts.map +1 -1
  103. package/dist/models-config/index.d.ts +8 -0
  104. package/dist/models-config/index.d.ts.map +1 -0
  105. package/dist/models-config/index.js +7 -0
  106. package/dist/models-config/index.js.map +1 -0
  107. package/dist/models-config/loader.d.ts +20 -0
  108. package/dist/models-config/loader.d.ts.map +1 -0
  109. package/dist/models-config/loader.js +85 -0
  110. package/dist/models-config/loader.js.map +1 -0
  111. package/dist/models-config/paths.d.ts +7 -0
  112. package/dist/models-config/paths.d.ts.map +1 -0
  113. package/dist/models-config/paths.js +11 -0
  114. package/dist/models-config/paths.js.map +1 -0
  115. package/dist/models-config/resolve.d.ts +57 -0
  116. package/dist/models-config/resolve.d.ts.map +1 -0
  117. package/dist/models-config/resolve.js +187 -0
  118. package/dist/models-config/resolve.js.map +1 -0
  119. package/dist/models-config/types.d.ts +60 -0
  120. package/dist/models-config/types.d.ts.map +1 -0
  121. package/dist/models-config/types.js +5 -0
  122. package/dist/models-config/types.js.map +1 -0
  123. package/dist/pytorch/process/index.d.ts +35 -0
  124. package/dist/pytorch/process/index.d.ts.map +1 -0
  125. package/dist/pytorch/process/index.js +69 -0
  126. package/dist/pytorch/process/index.js.map +1 -0
  127. package/dist/pytorch/pytorch-driver.d.ts +35 -0
  128. package/dist/pytorch/pytorch-driver.d.ts.map +1 -0
  129. package/dist/pytorch/pytorch-driver.js +48 -0
  130. package/dist/pytorch/pytorch-driver.js.map +1 -0
  131. package/dist/pytorch/pytorch-local-inference-adapters.d.ts +3 -0
  132. package/dist/pytorch/pytorch-local-inference-adapters.d.ts.map +1 -0
  133. package/dist/pytorch/pytorch-local-inference-adapters.js +19 -0
  134. package/dist/pytorch/pytorch-local-inference-adapters.js.map +1 -0
  135. package/dist/pytorch/pytorch-options.d.ts +8 -0
  136. package/dist/pytorch/pytorch-options.d.ts.map +1 -0
  137. package/dist/pytorch/pytorch-options.js +21 -0
  138. package/dist/pytorch/pytorch-options.js.map +1 -0
  139. package/dist/query-logger.js +1 -1
  140. package/dist/query-logger.js.map +1 -1
  141. package/dist/query-utils.d.ts +29 -0
  142. package/dist/query-utils.d.ts.map +1 -0
  143. package/dist/query-utils.js +61 -0
  144. package/dist/query-utils.js.map +1 -0
  145. package/dist/runtime/check.d.ts +10 -0
  146. package/dist/runtime/check.d.ts.map +1 -0
  147. package/dist/runtime/check.js +24 -0
  148. package/dist/runtime/check.js.map +1 -0
  149. package/dist/runtime/index.d.ts +4 -0
  150. package/dist/runtime/index.d.ts.map +1 -0
  151. package/dist/runtime/index.js +4 -0
  152. package/dist/runtime/index.js.map +1 -0
  153. package/dist/runtime/manifest-core.d.mts +27 -0
  154. package/dist/runtime/manifest-core.d.mts.map +1 -0
  155. package/dist/runtime/manifest-core.mjs +68 -0
  156. package/dist/runtime/manifest-core.mjs.map +1 -0
  157. package/dist/runtime/manifest.d.ts +18 -0
  158. package/dist/runtime/manifest.d.ts.map +1 -0
  159. package/dist/runtime/manifest.js +9 -0
  160. package/dist/runtime/manifest.js.map +1 -0
  161. package/dist/runtime/paths-core.d.mts +17 -0
  162. package/dist/runtime/paths-core.d.mts.map +1 -0
  163. package/dist/runtime/paths-core.mjs +67 -0
  164. package/dist/runtime/paths-core.mjs.map +1 -0
  165. package/dist/runtime/paths.d.ts +12 -0
  166. package/dist/runtime/paths.d.ts.map +1 -0
  167. package/dist/runtime/paths.js +17 -0
  168. package/dist/runtime/paths.js.map +1 -0
  169. package/dist/types.d.ts +20 -1
  170. package/dist/types.d.ts.map +1 -1
  171. package/dist/types.js.map +1 -1
  172. package/package.json +8 -5
  173. package/scripts/download-model.js +25 -9
  174. package/scripts/runtime-cli.js +315 -0
  175. package/skills/driver-usage/SKILL.md +56 -1
  176. package/src/mlx-ml/python/__main__.py +43 -4
  177. package/src/mlx-ml/python/handlers/__init__.py +2 -1
  178. package/src/mlx-ml/python/handlers/cancel.py +53 -0
  179. package/src/mlx-ml/python/handlers/completion.py +3 -24
  180. package/src/mlx-ml/python/handlers/{chat.py → generate.py} +36 -106
  181. package/src/mlx-ml/python/handlers/render.py +40 -0
  182. package/src/mlx-ml/python/pyproject.toml +3 -2
  183. package/src/mlx-ml/python/server.py +35 -8
  184. package/src/mlx-ml/python/utils/template_render.py +80 -0
  185. package/src/mlx-ml/python/utils/token_utils.py +2 -2
  186. package/src/mlx-ml/python/uv.lock +549 -454
  187. package/src/pytorch/python/__main__.py +19 -0
  188. package/src/pytorch/python/backends/__init__.py +3 -0
  189. package/src/pytorch/python/backends/base.py +84 -0
  190. package/src/pytorch/python/backends/transformers_lm.py +127 -0
  191. package/src/pytorch/python/handlers/__init__.py +6 -0
  192. package/src/pytorch/python/handlers/cancel.py +53 -0
  193. package/src/pytorch/python/handlers/capabilities.py +6 -0
  194. package/src/pytorch/python/handlers/completion.py +15 -0
  195. package/src/pytorch/python/handlers/format_test.py +70 -0
  196. package/src/pytorch/python/handlers/generate.py +68 -0
  197. package/src/pytorch/python/handlers/render.py +40 -0
  198. package/src/pytorch/python/handlers/tokenize.py +63 -0
  199. package/src/pytorch/python/pyproject.toml +36 -0
  200. package/src/pytorch/python/server.py +140 -0
  201. package/src/pytorch/python/utils/__init__.py +0 -0
  202. package/src/pytorch/python/utils/chat_template_constraints.py +164 -0
  203. package/src/pytorch/python/utils/prompt_builder.py +54 -0
  204. package/src/pytorch/python/utils/template_render.py +80 -0
  205. package/src/pytorch/python/utils/token_utils.py +376 -0
  206. package/src/pytorch/python/uv.lock +694 -0
  207. package/dist/mlx-ml/process/process-communication.d.ts +0 -37
  208. package/dist/mlx-ml/process/process-communication.d.ts.map +0 -1
  209. package/dist/mlx-ml/process/process-communication.js.map +0 -1
  210. package/dist/mlx-ml/process/queue.d.ts +0 -33
  211. package/dist/mlx-ml/process/queue.d.ts.map +0 -1
  212. package/dist/mlx-ml/process/queue.js.map +0 -1
  213. package/scripts/setup-mlx.js +0 -53
@@ -1,12 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ import os
4
5
  import re
5
6
  import sys
6
7
 
7
8
  from backends.base import ModelBackend
8
9
  from mlx_lm.models.cache import trim_prompt_cache
9
- from utils.prompt_builder import generate_merged_prompt, supports_chat_template
10
+ from handlers.cancel import poll_cancel
10
11
 
11
12
 
12
13
  def _read_cache_token_count(cache_path: str) -> int | None:
@@ -34,6 +35,8 @@ def _stream_to_stdout(
34
35
 
35
36
  last_response = None
36
37
  for response in backend.stream_generate(prompt, options, images, prompt_cache=prompt_cache):
38
+ if poll_cancel():
39
+ break
37
40
  print(response.text.replace("\0", "").replace("\x1e", ""), end="", flush=True)
38
41
  last_response = response
39
42
 
@@ -50,65 +53,42 @@ def _stream_to_stdout(
50
53
  print("", end="\0", flush=True)
51
54
 
52
55
 
53
- def handle_chat(
56
+ def handle_generate(
54
57
  backend: ModelBackend,
55
- capabilities: dict,
56
- messages: list,
57
- primer: str | None = None,
58
+ prompt: str | list[int],
58
59
  options: dict | None = None,
59
- tools: list | None = None,
60
60
  images: list | None = None,
61
61
  max_image_size: int = 768,
62
- reasoning_effort: str | None = None,
62
+ primer: str | None = None,
63
63
  cache_path: str | None = None,
64
64
  cache_trim_tokens: int | None = None,
65
65
  ) -> None:
66
- """chat API の処理"""
66
+ """LIP generate: 整形済み prompt のストリーム推論"""
67
67
  if options is None:
68
68
  options = {}
69
69
 
70
- tokenizer = backend.get_tokenizer()
71
-
72
- if backend.supports_vision():
73
- add_generation_prompt = True
74
- fmt_messages = list(messages)
75
- if primer is not None:
76
- fmt_messages.append({"role": "assistant", "content": primer})
77
- add_generation_prompt = False
78
-
79
- try:
80
- prompt = tokenizer.apply_chat_template(
81
- fmt_messages,
82
- tools=tools,
83
- add_generation_prompt=add_generation_prompt,
84
- tokenize=False,
85
- )
86
- except TypeError:
87
- prompt = tokenizer.apply_chat_template(
88
- fmt_messages,
89
- add_generation_prompt=add_generation_prompt,
90
- tokenize=False,
91
- )
92
-
93
- if primer is not None:
94
- prompt = primer.join(prompt.split(primer)[0:-1]) + primer
95
-
96
- display_prompt = re.sub(r'(<\|image_pad\|>)+', '<|image_pad|>...', prompt)
97
- sys.stderr.write(f"--- vlm prompt (images: {len(images) if images else 0}, max_size: {max_image_size})\n{display_prompt}\n")
98
-
99
- final_options = dict(options)
70
+ final_options = dict(options)
71
+ if images:
100
72
  final_options["max_image_size"] = max_image_size
101
- _stream_to_stdout(
102
- backend,
103
- prompt,
104
- final_options,
105
- images=images,
106
- primer=primer,
107
- )
108
- return
73
+ if os.getenv('MLX_DEBUG'):
74
+ if isinstance(prompt, str):
75
+ display_prompt = re.sub(r'(<\|image_pad\|>)+', '<|image_pad|>...', prompt)
76
+ else:
77
+ display_prompt = f"<token ids: len={len(prompt)}>"
78
+ sys.stderr.write(
79
+ f"--- vlm generate (images: {len(images)}, max_size: {max_image_size})\n{display_prompt}\n"
80
+ )
81
+ elif os.getenv('MLX_DEBUG'):
82
+ if isinstance(prompt, list):
83
+ sys.stderr.write(f"--- prompt: len={len(prompt)}\n")
84
+ else:
85
+ sys.stderr.write(f"--- prompt\n{prompt}\n")
109
86
 
110
- prompt_cache = backend.load_cache_from_file(cache_path) if cache_path else None
87
+ # VLM 経路では KV キャッシュを使わない(旧 chat ハンドラと同様)
88
+ prompt_cache = None
111
89
  cache_tokens = 0
90
+ if cache_path and not images:
91
+ prompt_cache = backend.load_cache_from_file(cache_path)
112
92
  if prompt_cache is not None:
113
93
  if cache_trim_tokens is not None:
114
94
  current_offset = backend.get_cache_offset(prompt_cache)
@@ -125,7 +105,6 @@ def handle_chat(
125
105
  if meta_count is not None:
126
106
  cache_tokens = meta_count
127
107
  else:
128
- # Legacy cache without meta file - skip it for safety
129
108
  sys.stderr.write(
130
109
  f"WARNING: Cache file exists but no .meta.json found at {cache_path}. "
131
110
  "Ignoring cache for safety (may be from old implementation).\n"
@@ -139,67 +118,11 @@ def handle_chat(
139
118
  elif cache_path:
140
119
  sys.stderr.write(f"KV cache load FAILED: {cache_path}\n")
141
120
 
142
- if not supports_chat_template(tokenizer):
143
- prompt = generate_merged_prompt(messages, capabilities)
144
- if prompt_cache is not None:
145
- sys.stderr.write("KV cache ignored: model does not support chat template\n")
146
- _stream_to_stdout(backend, prompt, options, primer=primer)
147
- return
148
-
149
- add_generation_prompt = True
150
- fmt_messages = list(messages)
151
- if primer is not None:
152
- fmt_messages.append({"role": "assistant", "content": primer})
153
- add_generation_prompt = False
154
-
155
- extra_kwargs = {}
156
- if tools is not None:
157
- extra_kwargs["tools"] = tools
158
- if reasoning_effort is not None:
159
- extra_kwargs["reasoning_effort"] = reasoning_effort
160
-
161
- trust_remote_code = options.get("trust_remote_code")
162
- if trust_remote_code is not None:
163
- extra_kwargs["trust_remote_code"] = trust_remote_code
164
-
165
- try:
166
- prompt = tokenizer.apply_chat_template(
167
- fmt_messages,
168
- add_generation_prompt=add_generation_prompt,
169
- tokenize=False,
170
- **extra_kwargs,
171
- )
172
- except TypeError:
173
- try:
174
- fallback_kwargs = {}
175
- if tools is not None:
176
- fallback_kwargs["tools"] = tools
177
- prompt = tokenizer.apply_chat_template(
178
- fmt_messages,
179
- add_generation_prompt=add_generation_prompt,
180
- tokenize=False,
181
- **fallback_kwargs,
182
- )
183
- except TypeError:
184
- prompt = tokenizer.apply_chat_template(
185
- fmt_messages,
186
- add_generation_prompt=add_generation_prompt,
187
- tokenize=False,
188
- )
189
-
190
- if primer is not None:
191
- prompt = primer.join(prompt.split(primer)[0:-1]) + primer
192
-
193
- if isinstance(prompt, list):
194
- sys.stderr.write(f"--- prompt: len={len(prompt)}\n")
195
- else:
196
- sys.stderr.write(f"--- prompt\n{prompt}\n")
197
-
198
- final_options = dict(options)
199
121
  final_options.pop("trust_remote_code", None)
200
122
 
201
123
  effective_prompt = prompt
202
124
  if prompt_cache is not None and cache_tokens > 0 and isinstance(prompt, str):
125
+ tokenizer = backend.get_tokenizer()
203
126
  add_special = tokenizer.bos_token is None or not prompt.startswith(
204
127
  tokenizer.bos_token
205
128
  )
@@ -218,4 +141,11 @@ def handle_chat(
218
141
  )
219
142
  prompt_cache = None
220
143
 
221
- _stream_to_stdout(backend, effective_prompt, final_options, primer=primer, prompt_cache=prompt_cache)
144
+ _stream_to_stdout(
145
+ backend,
146
+ effective_prompt,
147
+ final_options,
148
+ images=images,
149
+ primer=primer,
150
+ prompt_cache=prompt_cache,
151
+ )
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ from backends.base import ModelBackend
6
+ from utils.template_render import apply_chat_template_prompt
7
+
8
+
9
+ def handle_render(
10
+ backend: ModelBackend,
11
+ messages: list,
12
+ options: dict | None = None,
13
+ tools: list | None = None,
14
+ reasoning_effort: str | None = None,
15
+ ) -> None:
16
+ """LIP render: apply_chat_template のみ(推論しない)"""
17
+ if options is None:
18
+ options = {}
19
+
20
+ result: dict = {
21
+ "formatted_prompt": None,
22
+ "error": None,
23
+ }
24
+
25
+ try:
26
+ trust_remote_code = options.get("trust_remote_code")
27
+ primer = options.get("primer")
28
+ prompt = apply_chat_template_prompt(
29
+ backend,
30
+ messages,
31
+ primer=primer,
32
+ tools=tools,
33
+ reasoning_effort=reasoning_effort,
34
+ trust_remote_code=trust_remote_code,
35
+ )
36
+ result["formatted_prompt"] = prompt
37
+ except Exception as e:
38
+ result["error"] = str(e)
39
+
40
+ print(json.dumps(result), end="\0", flush=True)
@@ -2,14 +2,15 @@
2
2
  name = "mlx_driver"
3
3
  version = "0.1.0"
4
4
  description = "MLX driver for moduler-prompt"
5
- requires-python = ">=3.10,<3.14"
5
+ requires-python = ">=3.11,<3.14"
6
6
  dependencies = [
7
7
  "flex==6.14.1",
8
8
  "hf-xet==1.2.0",
9
9
  "jinja2==3.1.6",
10
10
  "mlx>=0.31.2; sys_platform == 'darwin'",
11
11
  "mlx-lm==0.31.3; sys_platform == 'darwin'",
12
- "mlx-vlm==0.6.3; sys_platform == 'darwin'",
12
+ "mlx-optiq>=0.4.4; sys_platform == 'darwin'",
13
+ "mlx-vlm==0.6.4; sys_platform == 'darwin'",
13
14
  "tokenizers==0.22.2",
14
15
  "torch==2.9.1",
15
16
  "torchvision==0.24.1",
@@ -3,7 +3,8 @@ import json
3
3
  import sys
4
4
 
5
5
  from backends.base import ModelBackend
6
- from handlers import handle_cache_prefill, handle_capabilities, handle_chat, handle_completion, handle_format_test, handle_tokenize
6
+ from handlers import handle_cache_prefill, handle_capabilities, handle_completion, handle_format_test, handle_generate, handle_render, handle_tokenize
7
+ from handlers.cancel import request_cancel, reset_cancel
7
8
 
8
9
 
9
10
  MAX_READ_LINES = 10000
@@ -26,6 +27,15 @@ def read():
26
27
  continue
27
28
 
28
29
 
30
+ def _is_valid_generate_prompt(prompt) -> bool:
31
+ """prompt は非空文字列または非空のトークン ID リスト"""
32
+ if isinstance(prompt, str):
33
+ return bool(prompt)
34
+ if isinstance(prompt, list):
35
+ return len(prompt) > 0
36
+ return False
37
+
38
+
29
39
  class Server:
30
40
  def __init__(self, backend: ModelBackend, capabilities: dict):
31
41
  self.backend = backend
@@ -48,6 +58,12 @@ class Server:
48
58
  self._error_response("'method' field is required")
49
59
  return
50
60
 
61
+ if method == 'cancel':
62
+ request_cancel()
63
+ return
64
+
65
+ reset_cancel()
66
+
51
67
  try:
52
68
  if method == 'capabilities':
53
69
  handle_capabilities(self.capabilities)
@@ -86,21 +102,32 @@ class Server:
86
102
  reasoning_effort=req.get('reasoning_effort'),
87
103
  )
88
104
 
89
- elif method == 'chat':
105
+ elif method == 'render':
90
106
  messages = req.get('messages')
91
107
  if not messages:
92
- self._error_response("'messages' field is required for chat method")
108
+ self._error_response("'messages' field is required for render method")
93
109
  return
94
- handle_chat(
110
+ handle_render(
95
111
  self.backend,
96
- self.capabilities,
97
112
  messages,
98
- primer=req.get('primer'),
99
113
  options=req.get('options', {}),
100
114
  tools=req.get('tools'),
101
- images=req.get('images', []),
102
- max_image_size=req.get('maxImageSize', 768),
103
115
  reasoning_effort=req.get('reasoning_effort'),
116
+ )
117
+
118
+ elif method == 'generate':
119
+ prompt = req.get('prompt')
120
+ if not _is_valid_generate_prompt(prompt):
121
+ self._error_response("'prompt' field is required for generate method")
122
+ return
123
+ images = req.get('images', [])
124
+ handle_generate(
125
+ self.backend,
126
+ prompt,
127
+ options=req.get('options', {}),
128
+ images=images if images else None,
129
+ max_image_size=req.get('maxImageSize', 768),
130
+ primer=req.get('primer'),
104
131
  cache_path=req.get('cache_path'),
105
132
  cache_trim_tokens=req.get('cache_trim_tokens'),
106
133
  )
@@ -0,0 +1,80 @@
1
+ """apply_chat_template によるプロンプト整形(推論なし)"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from utils.prompt_builder import supports_chat_template
6
+
7
+
8
+ def apply_chat_template_prompt(
9
+ backend,
10
+ messages: list,
11
+ *,
12
+ primer: str | None = None,
13
+ tools: list | None = None,
14
+ reasoning_effort: str | None = None,
15
+ trust_remote_code: bool | None = None,
16
+ ) -> str | list:
17
+ """messages を chat template で整形して prompt を返す"""
18
+ tokenizer = backend.get_tokenizer()
19
+
20
+ if not supports_chat_template(tokenizer):
21
+ raise ValueError("chat_template_not_available")
22
+
23
+ add_generation_prompt = True
24
+ fmt_messages = list(messages)
25
+ if primer is not None:
26
+ fmt_messages.append({"role": "assistant", "content": primer})
27
+ add_generation_prompt = False
28
+
29
+ if backend.supports_vision():
30
+ try:
31
+ prompt = tokenizer.apply_chat_template(
32
+ fmt_messages,
33
+ tools=tools,
34
+ add_generation_prompt=add_generation_prompt,
35
+ tokenize=False,
36
+ )
37
+ except TypeError:
38
+ prompt = tokenizer.apply_chat_template(
39
+ fmt_messages,
40
+ add_generation_prompt=add_generation_prompt,
41
+ tokenize=False,
42
+ )
43
+ else:
44
+ extra_kwargs: dict = {}
45
+ if tools is not None:
46
+ extra_kwargs["tools"] = tools
47
+ if reasoning_effort is not None:
48
+ extra_kwargs["reasoning_effort"] = reasoning_effort
49
+ if trust_remote_code is not None:
50
+ extra_kwargs["trust_remote_code"] = trust_remote_code
51
+
52
+ try:
53
+ prompt = tokenizer.apply_chat_template(
54
+ fmt_messages,
55
+ add_generation_prompt=add_generation_prompt,
56
+ tokenize=False,
57
+ **extra_kwargs,
58
+ )
59
+ except TypeError:
60
+ try:
61
+ fallback_kwargs: dict = {}
62
+ if tools is not None:
63
+ fallback_kwargs["tools"] = tools
64
+ prompt = tokenizer.apply_chat_template(
65
+ fmt_messages,
66
+ add_generation_prompt=add_generation_prompt,
67
+ tokenize=False,
68
+ **fallback_kwargs,
69
+ )
70
+ except TypeError:
71
+ prompt = tokenizer.apply_chat_template(
72
+ fmt_messages,
73
+ add_generation_prompt=add_generation_prompt,
74
+ tokenize=False,
75
+ )
76
+
77
+ if primer is not None and isinstance(prompt, str):
78
+ prompt = primer.join(prompt.split(primer)[0:-1]) + primer
79
+
80
+ return prompt
@@ -342,11 +342,11 @@ def get_capabilities(tokenizer):
342
342
  dict: capabilities情報
343
343
  """
344
344
  # 基本メソッド
345
- methods = ["capabilities", "completion", "format_test"]
345
+ methods = ["capabilities", "completion", "generate", "format_test"]
346
346
 
347
347
  # apply_chat_templateがある場合はchatメソッドを追加
348
348
  if hasattr(tokenizer, 'apply_chat_template'):
349
- methods.append("chat")
349
+ methods.append("render")
350
350
 
351
351
  capabilities = {
352
352
  "methods": methods,