@modular-prompt/driver 0.14.0 → 0.16.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 +90 -5
- package/dist/driver-registry/ai-service.d.ts +23 -1
- package/dist/driver-registry/ai-service.d.ts.map +1 -1
- package/dist/driver-registry/ai-service.js +44 -10
- package/dist/driver-registry/ai-service.js.map +1 -1
- package/dist/driver-registry/config-based-factory.d.ts.map +1 -1
- package/dist/driver-registry/config-based-factory.js +20 -3
- package/dist/driver-registry/config-based-factory.js.map +1 -1
- package/dist/driver-registry/factory-helper.d.ts +2 -0
- package/dist/driver-registry/factory-helper.d.ts.map +1 -1
- package/dist/driver-registry/factory-helper.js +22 -3
- package/dist/driver-registry/factory-helper.js.map +1 -1
- package/dist/driver-registry/index.d.ts +2 -2
- package/dist/driver-registry/index.d.ts.map +1 -1
- package/dist/driver-registry/index.js +1 -1
- package/dist/driver-registry/index.js.map +1 -1
- package/dist/driver-registry/registry.d.ts.map +1 -1
- package/dist/driver-registry/registry.js +3 -1
- package/dist/driver-registry/registry.js.map +1 -1
- package/dist/driver-registry/types.d.ts +11 -2
- package/dist/driver-registry/types.d.ts.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/local-inference/adapters.d.ts +66 -0
- package/dist/local-inference/adapters.d.ts.map +1 -0
- package/dist/local-inference/adapters.js +2 -0
- package/dist/local-inference/adapters.js.map +1 -0
- package/dist/local-inference/driver.d.ts +51 -0
- package/dist/local-inference/driver.d.ts.map +1 -0
- package/dist/local-inference/driver.js +309 -0
- package/dist/local-inference/driver.js.map +1 -0
- package/dist/local-inference/index.d.ts +22 -0
- package/dist/local-inference/index.d.ts.map +1 -0
- package/dist/local-inference/index.js +17 -0
- package/dist/local-inference/index.js.map +1 -0
- package/dist/local-inference/process-client.d.ts +50 -0
- package/dist/local-inference/process-client.d.ts.map +1 -0
- package/dist/local-inference/process-client.js +92 -0
- package/dist/local-inference/process-client.js.map +1 -0
- package/dist/local-inference/process-communication.d.ts +41 -0
- package/dist/local-inference/process-communication.d.ts.map +1 -0
- package/dist/{mlx-ml/process → local-inference}/process-communication.js +25 -61
- package/dist/local-inference/process-communication.js.map +1 -0
- package/dist/local-inference/process-port.d.ts +12 -0
- package/dist/local-inference/process-port.d.ts.map +1 -0
- package/dist/local-inference/process-port.js +2 -0
- package/dist/local-inference/process-port.js.map +1 -0
- package/dist/local-inference/prompt-utils.d.ts +6 -0
- package/dist/local-inference/prompt-utils.d.ts.map +1 -0
- package/dist/local-inference/prompt-utils.js +17 -0
- package/dist/local-inference/prompt-utils.js.map +1 -0
- package/dist/local-inference/protocol.d.ts +192 -0
- package/dist/local-inference/protocol.d.ts.map +1 -0
- package/dist/local-inference/protocol.js +2 -0
- package/dist/local-inference/protocol.js.map +1 -0
- package/dist/local-inference/queue-types.d.ts +54 -0
- package/dist/local-inference/queue-types.d.ts.map +1 -0
- package/dist/local-inference/queue-types.js +2 -0
- package/dist/local-inference/queue-types.js.map +1 -0
- package/dist/local-inference/request-queue.d.ts +36 -0
- package/dist/local-inference/request-queue.d.ts.map +1 -0
- package/dist/{mlx-ml/process/queue.js → local-inference/request-queue.js} +83 -56
- package/dist/local-inference/request-queue.js.map +1 -0
- package/dist/local-inference/stream-utils.d.ts +19 -0
- package/dist/local-inference/stream-utils.d.ts.map +1 -0
- package/dist/local-inference/stream-utils.js +76 -0
- package/dist/local-inference/stream-utils.js.map +1 -0
- package/dist/mlx-ml/mlx-cache-controller.d.ts.map +1 -1
- package/dist/mlx-ml/mlx-cache-controller.js +2 -1
- package/dist/mlx-ml/mlx-cache-controller.js.map +1 -1
- package/dist/mlx-ml/mlx-cache-support.d.ts +23 -0
- package/dist/mlx-ml/mlx-cache-support.d.ts.map +1 -0
- package/dist/mlx-ml/mlx-cache-support.js +45 -0
- package/dist/mlx-ml/mlx-cache-support.js.map +1 -0
- package/dist/mlx-ml/mlx-driver.d.ts +20 -59
- package/dist/mlx-ml/mlx-driver.d.ts.map +1 -1
- package/dist/mlx-ml/mlx-driver.js +86 -460
- package/dist/mlx-ml/mlx-driver.js.map +1 -1
- package/dist/mlx-ml/mlx-local-inference-adapters.d.ts +3 -0
- package/dist/mlx-ml/mlx-local-inference-adapters.d.ts.map +1 -0
- package/dist/mlx-ml/mlx-local-inference-adapters.js +19 -0
- package/dist/mlx-ml/mlx-local-inference-adapters.js.map +1 -0
- package/dist/mlx-ml/mlx-options.d.ts +19 -0
- package/dist/mlx-ml/mlx-options.d.ts.map +1 -0
- package/dist/mlx-ml/mlx-options.js +30 -0
- package/dist/mlx-ml/mlx-options.js.map +1 -0
- package/dist/mlx-ml/process/index.d.ts +10 -8
- package/dist/mlx-ml/process/index.d.ts.map +1 -1
- package/dist/mlx-ml/process/index.js +73 -54
- package/dist/mlx-ml/process/index.js.map +1 -1
- package/dist/mlx-ml/process/model-specific.d.ts +2 -1
- package/dist/mlx-ml/process/model-specific.d.ts.map +1 -1
- package/dist/mlx-ml/process/model-specific.js.map +1 -1
- package/dist/mlx-ml/process/prompt-builder.d.ts +11 -0
- package/dist/mlx-ml/process/prompt-builder.d.ts.map +1 -0
- package/dist/mlx-ml/process/prompt-builder.js +51 -0
- package/dist/mlx-ml/process/prompt-builder.js.map +1 -0
- package/dist/mlx-ml/process/types.d.ts +15 -183
- package/dist/mlx-ml/process/types.d.ts.map +1 -1
- package/dist/mlx-ml/types.d.ts +2 -45
- package/dist/mlx-ml/types.d.ts.map +1 -1
- package/dist/models-config/index.d.ts +8 -0
- package/dist/models-config/index.d.ts.map +1 -0
- package/dist/models-config/index.js +7 -0
- package/dist/models-config/index.js.map +1 -0
- package/dist/models-config/loader.d.ts +20 -0
- package/dist/models-config/loader.d.ts.map +1 -0
- package/dist/models-config/loader.js +85 -0
- package/dist/models-config/loader.js.map +1 -0
- package/dist/models-config/paths.d.ts +15 -0
- package/dist/models-config/paths.d.ts.map +1 -0
- package/dist/models-config/paths.js +26 -0
- package/dist/models-config/paths.js.map +1 -0
- package/dist/models-config/resolve.d.ts +57 -0
- package/dist/models-config/resolve.d.ts.map +1 -0
- package/dist/models-config/resolve.js +208 -0
- package/dist/models-config/resolve.js.map +1 -0
- package/dist/models-config/types.d.ts +62 -0
- package/dist/models-config/types.d.ts.map +1 -0
- package/dist/models-config/types.js +5 -0
- package/dist/models-config/types.js.map +1 -0
- package/dist/pytorch/process/index.d.ts +35 -0
- package/dist/pytorch/process/index.d.ts.map +1 -0
- package/dist/pytorch/process/index.js +69 -0
- package/dist/pytorch/process/index.js.map +1 -0
- package/dist/pytorch/pytorch-driver.d.ts +35 -0
- package/dist/pytorch/pytorch-driver.d.ts.map +1 -0
- package/dist/pytorch/pytorch-driver.js +48 -0
- package/dist/pytorch/pytorch-driver.js.map +1 -0
- package/dist/pytorch/pytorch-local-inference-adapters.d.ts +3 -0
- package/dist/pytorch/pytorch-local-inference-adapters.d.ts.map +1 -0
- package/dist/pytorch/pytorch-local-inference-adapters.js +19 -0
- package/dist/pytorch/pytorch-local-inference-adapters.js.map +1 -0
- package/dist/pytorch/pytorch-options.d.ts +8 -0
- package/dist/pytorch/pytorch-options.d.ts.map +1 -0
- package/dist/pytorch/pytorch-options.js +21 -0
- package/dist/pytorch/pytorch-options.js.map +1 -0
- package/dist/query-logger.js +1 -1
- package/dist/query-logger.js.map +1 -1
- package/dist/runtime/check.d.ts +10 -0
- package/dist/runtime/check.d.ts.map +1 -0
- package/dist/runtime/check.js +25 -0
- package/dist/runtime/check.js.map +1 -0
- package/dist/runtime/index.d.ts +5 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +5 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/manifest-core.d.mts +27 -0
- package/dist/runtime/manifest-core.d.mts.map +1 -0
- package/dist/runtime/manifest-core.mjs +68 -0
- package/dist/runtime/manifest-core.mjs.map +1 -0
- package/dist/runtime/manifest.d.ts +18 -0
- package/dist/runtime/manifest.d.ts.map +1 -0
- package/dist/runtime/manifest.js +9 -0
- package/dist/runtime/manifest.js.map +1 -0
- package/dist/runtime/paths-core.d.mts +17 -0
- package/dist/runtime/paths-core.d.mts.map +1 -0
- package/dist/runtime/paths-core.mjs +67 -0
- package/dist/runtime/paths-core.mjs.map +1 -0
- package/dist/runtime/paths.d.ts +12 -0
- package/dist/runtime/paths.d.ts.map +1 -0
- package/dist/runtime/paths.js +17 -0
- package/dist/runtime/paths.js.map +1 -0
- package/dist/runtime/setup-commands-core.d.mts +13 -0
- package/dist/runtime/setup-commands-core.d.mts.map +1 -0
- package/dist/runtime/setup-commands-core.mjs +14 -0
- package/dist/runtime/setup-commands-core.mjs.map +1 -0
- package/dist/runtime/setup-commands.d.ts +2 -0
- package/dist/runtime/setup-commands.d.ts.map +1 -0
- package/dist/runtime/setup-commands.js +2 -0
- package/dist/runtime/setup-commands.js.map +1 -0
- package/dist/types.d.ts +11 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +13 -7
- package/scripts/download-model.js +26 -9
- package/scripts/runtime-cli.js +320 -0
- package/src/mlx-ml/python/__main__.py +43 -4
- package/src/mlx-ml/python/backends/cache_archive.py +41 -0
- package/src/mlx-ml/python/backends/mlx_lm.py +17 -1
- package/src/mlx-ml/python/handlers/__init__.py +2 -1
- package/src/mlx-ml/python/handlers/completion.py +3 -27
- package/src/mlx-ml/python/handlers/{chat.py → generate.py} +33 -106
- package/src/mlx-ml/python/handlers/render.py +40 -0
- package/src/mlx-ml/python/pyproject.toml +11 -4
- package/src/mlx-ml/python/server.py +28 -8
- package/src/mlx-ml/python/utils/template_render.py +80 -0
- package/src/mlx-ml/python/utils/token_utils.py +2 -2
- package/src/mlx-ml/python/uv.lock +544 -689
- package/src/pytorch/python/__main__.py +19 -0
- package/src/pytorch/python/backends/__init__.py +3 -0
- package/src/pytorch/python/backends/base.py +84 -0
- package/src/pytorch/python/backends/transformers_lm.py +127 -0
- package/src/pytorch/python/handlers/__init__.py +6 -0
- package/src/pytorch/python/handlers/cancel.py +53 -0
- package/src/pytorch/python/handlers/capabilities.py +6 -0
- package/src/pytorch/python/handlers/completion.py +15 -0
- package/src/pytorch/python/handlers/format_test.py +70 -0
- package/src/pytorch/python/handlers/generate.py +68 -0
- package/src/pytorch/python/handlers/render.py +40 -0
- package/src/pytorch/python/handlers/tokenize.py +63 -0
- package/src/pytorch/python/pyproject.toml +36 -0
- package/src/pytorch/python/server.py +140 -0
- package/src/pytorch/python/utils/__init__.py +0 -0
- package/src/pytorch/python/utils/chat_template_constraints.py +164 -0
- package/src/pytorch/python/utils/prompt_builder.py +54 -0
- package/src/pytorch/python/utils/template_render.py +80 -0
- package/src/pytorch/python/utils/token_utils.py +376 -0
- package/src/pytorch/python/uv.lock +694 -0
- package/dist/mlx-ml/process/process-communication.d.ts +0 -45
- package/dist/mlx-ml/process/process-communication.d.ts.map +0 -1
- package/dist/mlx-ml/process/process-communication.js.map +0 -1
- package/dist/mlx-ml/process/queue.d.ts +0 -35
- package/dist/mlx-ml/process/queue.d.ts.map +0 -1
- package/dist/mlx-ml/process/queue.js.map +0 -1
- package/scripts/setup-mlx.js +0 -53
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Python runtime 管理 CLI
|
|
5
|
+
*
|
|
6
|
+
* setup mlx — ~/.modular-prompt/runtimes/mlx に venv を作成
|
|
7
|
+
* setup pytorch — ~/.modular-prompt/runtimes/pytorch に cpu-minimal venv を作成
|
|
8
|
+
* setup --status
|
|
9
|
+
* cleanup mlx [--yes]
|
|
10
|
+
* cleanup --all [--yes]
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { execSync } from 'child_process';
|
|
14
|
+
import { existsSync, readFileSync, rmSync, mkdirSync } from 'fs';
|
|
15
|
+
import { createInterface } from 'readline';
|
|
16
|
+
import { dirname, join } from 'path';
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const packageRoot = join(__dirname, '..');
|
|
21
|
+
const driverVersion = readPackageVersion();
|
|
22
|
+
|
|
23
|
+
function runtimeModuleUrl(name) {
|
|
24
|
+
const distPath = join(packageRoot, 'dist', 'runtime', name);
|
|
25
|
+
const srcPath = join(packageRoot, 'src', 'runtime', name);
|
|
26
|
+
return pathToFileURL(existsSync(distPath) ? distPath : srcPath).href;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
RUNTIME_PROFILES,
|
|
31
|
+
getModularPromptHome,
|
|
32
|
+
getRuntimeDir,
|
|
33
|
+
getVenvPath,
|
|
34
|
+
getMlxPythonDir,
|
|
35
|
+
getPytorchPythonDir,
|
|
36
|
+
isRuntimeReady,
|
|
37
|
+
} = await import(runtimeModuleUrl('paths-core.mjs'));
|
|
38
|
+
|
|
39
|
+
const {
|
|
40
|
+
SETUP_MLX_MONOREPO,
|
|
41
|
+
SETUP_PYTORCH_MONOREPO,
|
|
42
|
+
} = await import(runtimeModuleUrl('setup-commands-core.mjs'));
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
collectInstalledPackages,
|
|
46
|
+
readManifest,
|
|
47
|
+
writeManifest,
|
|
48
|
+
} = await import(runtimeModuleUrl('manifest-core.mjs'));
|
|
49
|
+
|
|
50
|
+
function readPackageVersion() {
|
|
51
|
+
try {
|
|
52
|
+
const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
|
|
53
|
+
return pkg.version ?? 'unknown';
|
|
54
|
+
} catch {
|
|
55
|
+
return 'unknown';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function ensureUv() {
|
|
60
|
+
try {
|
|
61
|
+
execSync('uv --version', { stdio: 'ignore' });
|
|
62
|
+
return;
|
|
63
|
+
} catch {
|
|
64
|
+
console.log('⚠️ uv is not installed. Installing uv...');
|
|
65
|
+
execSync('curl -LsSf https://astral.sh/uv/install.sh | sh', { stdio: 'inherit' });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function setupMlx() {
|
|
70
|
+
if (process.platform !== 'darwin') {
|
|
71
|
+
console.error('❌ MLX runtime is only available on macOS (Apple Silicon).');
|
|
72
|
+
console.error(' For local inference on this platform, use setup-pytorch or vLLM.');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const pythonDir = getMlxPythonDir(packageRoot);
|
|
77
|
+
if (!existsSync(pythonDir)) {
|
|
78
|
+
console.error(`❌ MLX Python project not found: ${pythonDir}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const venvPath = getVenvPath('mlx');
|
|
83
|
+
const runtimeDir = getRuntimeDir('mlx');
|
|
84
|
+
|
|
85
|
+
console.log('🚀 Setting up MLX runtime...\n');
|
|
86
|
+
console.log(`📁 Python project: ${pythonDir}`);
|
|
87
|
+
console.log(`📁 Runtime venv: ${venvPath}\n`);
|
|
88
|
+
|
|
89
|
+
ensureUv();
|
|
90
|
+
mkdirSync(runtimeDir, { recursive: true });
|
|
91
|
+
|
|
92
|
+
const env = {
|
|
93
|
+
...process.env,
|
|
94
|
+
UV_PROJECT_ENVIRONMENT: venvPath,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
execSync('uv venv --clear --python 3.13', { cwd: pythonDir, stdio: 'inherit', env });
|
|
99
|
+
execSync('uv pip install -e .', { cwd: pythonDir, stdio: 'inherit', env });
|
|
100
|
+
|
|
101
|
+
writeManifest('mlx', {
|
|
102
|
+
profile: 'mlx',
|
|
103
|
+
driverVersion,
|
|
104
|
+
platform: process.platform,
|
|
105
|
+
pythonVersion: '3.13',
|
|
106
|
+
createdAt: new Date().toISOString(),
|
|
107
|
+
packages: collectInstalledPackages(pythonDir, venvPath),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
console.log('\n✅ MLX runtime setup completed.');
|
|
111
|
+
console.log(` Home: ${getModularPromptHome()}`);
|
|
112
|
+
console.log(' You can now use MlxDriver from @modular-prompt/driver');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
115
|
+
console.error('❌ Failed to setup MLX runtime:', message);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const PYTORCH_CPU_INDEX = 'https://download.pytorch.org/whl/cpu';
|
|
121
|
+
const PYTORCH_PYTHON_VERSION = '3.12';
|
|
122
|
+
|
|
123
|
+
function setupPytorch() {
|
|
124
|
+
const pythonDir = getPytorchPythonDir(packageRoot);
|
|
125
|
+
if (!existsSync(pythonDir)) {
|
|
126
|
+
console.error(`❌ PyTorch Python project not found: ${pythonDir}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const venvPath = getVenvPath('pytorch');
|
|
131
|
+
const runtimeDir = getRuntimeDir('pytorch');
|
|
132
|
+
|
|
133
|
+
console.log('🚀 Setting up PyTorch runtime (cpu-minimal)...\n');
|
|
134
|
+
console.log(`📁 Python project: ${pythonDir}`);
|
|
135
|
+
console.log(`📁 Runtime venv: ${venvPath}`);
|
|
136
|
+
console.log(`📦 torch index: ${PYTORCH_CPU_INDEX}\n`);
|
|
137
|
+
|
|
138
|
+
ensureUv();
|
|
139
|
+
mkdirSync(runtimeDir, { recursive: true });
|
|
140
|
+
|
|
141
|
+
const env = {
|
|
142
|
+
...process.env,
|
|
143
|
+
UV_PROJECT_ENVIRONMENT: venvPath,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
execSync(`uv venv --clear --python ${PYTORCH_PYTHON_VERSION}`, { cwd: pythonDir, stdio: 'inherit', env });
|
|
148
|
+
const venvPython =
|
|
149
|
+
process.platform === 'win32'
|
|
150
|
+
? join(venvPath, 'Scripts', 'python.exe')
|
|
151
|
+
: join(venvPath, 'bin', 'python');
|
|
152
|
+
execSync(`uv pip install --python "${venvPython}" "torch==2.9.1" --index-url ${PYTORCH_CPU_INDEX}`, {
|
|
153
|
+
cwd: pythonDir,
|
|
154
|
+
stdio: 'inherit',
|
|
155
|
+
env,
|
|
156
|
+
});
|
|
157
|
+
execSync(`uv pip install --python "${venvPython}" -e .`, { cwd: pythonDir, stdio: 'inherit', env });
|
|
158
|
+
|
|
159
|
+
const packages = collectInstalledPackages(pythonDir, venvPath);
|
|
160
|
+
writeManifest('pytorch', {
|
|
161
|
+
profile: 'pytorch',
|
|
162
|
+
variant: 'cpu-minimal',
|
|
163
|
+
driverVersion,
|
|
164
|
+
platform: process.platform,
|
|
165
|
+
pythonVersion: PYTORCH_PYTHON_VERSION,
|
|
166
|
+
torchVersion: packages?.torch,
|
|
167
|
+
createdAt: new Date().toISOString(),
|
|
168
|
+
packages,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
console.log('\n✅ PyTorch runtime setup completed (cpu-minimal).');
|
|
172
|
+
console.log(` Home: ${getModularPromptHome()}`);
|
|
173
|
+
console.log(' You can now use PyTorchDriver from @modular-prompt/driver');
|
|
174
|
+
console.log(' For CUDA / custom environments, see docs/LOCAL_MODEL_SETUP.md');
|
|
175
|
+
} catch (error) {
|
|
176
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
177
|
+
console.error('❌ Failed to setup PyTorch runtime:', message);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function formatManifestDetail(manifest) {
|
|
183
|
+
const parts = [`driver ${manifest.driverVersion}`];
|
|
184
|
+
if (manifest.variant) {
|
|
185
|
+
parts.push(`variant ${manifest.variant}`);
|
|
186
|
+
}
|
|
187
|
+
const torchVersion = manifest.torchVersion ?? manifest.packages?.torch;
|
|
188
|
+
if (torchVersion) {
|
|
189
|
+
parts.push(`torch ${torchVersion}`);
|
|
190
|
+
}
|
|
191
|
+
parts.push(manifest.createdAt);
|
|
192
|
+
return ` (${parts.join(', ')})`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function printStatus() {
|
|
196
|
+
console.log(`modular-prompt home: ${getModularPromptHome()}\n`);
|
|
197
|
+
for (const profile of RUNTIME_PROFILES) {
|
|
198
|
+
const ready = isRuntimeReady(profile);
|
|
199
|
+
const manifest = ready ? readManifest(profile) : null;
|
|
200
|
+
const detail = manifest ? formatManifestDetail(manifest) : '';
|
|
201
|
+
const icon = ready ? '✅' : '❌';
|
|
202
|
+
const runtimePath = getRuntimeDir(profile);
|
|
203
|
+
console.log(`${icon} ${profile}: ${ready ? 'ready' : 'not installed'}${detail}`);
|
|
204
|
+
console.log(` ${runtimePath}`);
|
|
205
|
+
}
|
|
206
|
+
const setupHints = [];
|
|
207
|
+
if (!isRuntimeReady('mlx') && process.platform === 'darwin') {
|
|
208
|
+
setupHints.push(SETUP_MLX_MONOREPO);
|
|
209
|
+
}
|
|
210
|
+
if (!isRuntimeReady('pytorch')) {
|
|
211
|
+
setupHints.push(SETUP_PYTORCH_MONOREPO);
|
|
212
|
+
}
|
|
213
|
+
if (setupHints.length > 0) {
|
|
214
|
+
console.log(`\nRun: ${setupHints.join(' or ')}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function confirm(message) {
|
|
219
|
+
if (process.argv.includes('--yes') || process.argv.includes('-y')) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
223
|
+
const answer = await new Promise((resolve) => {
|
|
224
|
+
rl.question(`${message} [y/N] `, resolve);
|
|
225
|
+
});
|
|
226
|
+
rl.close();
|
|
227
|
+
return String(answer).toLowerCase() === 'y' || String(answer).toLowerCase() === 'yes';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function cleanupProfile(profile) {
|
|
231
|
+
if (!existsSync(getRuntimeDir(profile))) {
|
|
232
|
+
console.log(`ℹ️ ${profile}: nothing to clean (${getRuntimeDir(profile)} does not exist)`);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const ok = await confirm(`Delete ${profile} runtime at ${getRuntimeDir(profile)}?`);
|
|
236
|
+
if (!ok) {
|
|
237
|
+
console.log('Cancelled.');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
rmSync(getRuntimeDir(profile), { recursive: true, force: true });
|
|
241
|
+
console.log(`✅ Removed ${profile} runtime.`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function cleanupAll() {
|
|
245
|
+
const home = getModularPromptHome();
|
|
246
|
+
if (!existsSync(home)) {
|
|
247
|
+
console.log(`ℹ️ Nothing to clean (${home} does not exist)`);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const ok = await confirm(`Delete entire modular-prompt home at ${home}?`);
|
|
251
|
+
if (!ok) {
|
|
252
|
+
console.log('Cancelled.');
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
rmSync(home, { recursive: true, force: true });
|
|
256
|
+
console.log(`✅ Removed ${home}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function printUsage() {
|
|
260
|
+
console.log(`Usage:
|
|
261
|
+
modular-prompt-runtime setup mlx Set up MLX Python runtime (macOS only)
|
|
262
|
+
modular-prompt-runtime setup pytorch Set up PyTorch runtime (cpu-minimal)
|
|
263
|
+
modular-prompt-runtime setup --status Show runtime status
|
|
264
|
+
modular-prompt-runtime cleanup mlx Remove MLX runtime
|
|
265
|
+
modular-prompt-runtime cleanup pytorch Remove PyTorch runtime
|
|
266
|
+
modular-prompt-runtime cleanup --all Remove entire ~/.modular-prompt
|
|
267
|
+
modular-prompt-runtime cleanup ... --yes Skip confirmation
|
|
268
|
+
|
|
269
|
+
npm scripts: setup-mlx, setup-pytorch, runtime:status, runtime:cleanup`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function main() {
|
|
273
|
+
const [command, target] = process.argv.slice(2);
|
|
274
|
+
|
|
275
|
+
if (!command || command === '--help' || command === '-h') {
|
|
276
|
+
printUsage();
|
|
277
|
+
process.exit(0);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (command === 'setup') {
|
|
281
|
+
if (target === '--status' || target === 'status') {
|
|
282
|
+
printStatus();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (target === 'mlx') {
|
|
286
|
+
setupMlx();
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (target === 'pytorch') {
|
|
290
|
+
setupPytorch();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
console.error(`Unknown setup target: ${target ?? '(none)'}`);
|
|
294
|
+
printUsage();
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (command === 'cleanup') {
|
|
299
|
+
if (target === '--all' || target === 'all') {
|
|
300
|
+
await cleanupAll();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (target === 'mlx' || target === 'pytorch') {
|
|
304
|
+
await cleanupProfile(target);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
console.error(`Unknown cleanup target: ${target ?? '(none)'}`);
|
|
308
|
+
printUsage();
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
console.error(`Unknown command: ${command}`);
|
|
313
|
+
printUsage();
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
main().catch((error) => {
|
|
318
|
+
console.error(error);
|
|
319
|
+
process.exit(1);
|
|
320
|
+
});
|
|
@@ -6,7 +6,28 @@ from utils.vlm_utils import detect_model_kind
|
|
|
6
6
|
from server import Server
|
|
7
7
|
|
|
8
8
|
model_name = sys.argv[1] if len(sys.argv) > 1 else "mlx-community/gemma-3-270m-it-qat-4bit"
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
VALID_BACKENDS = {"auto", "lm", "vlm", "optiq"}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def parse_backend_mode() -> str:
|
|
14
|
+
if "--backend" in sys.argv:
|
|
15
|
+
idx = sys.argv.index("--backend")
|
|
16
|
+
if idx + 1 < len(sys.argv):
|
|
17
|
+
mode = sys.argv[idx + 1]
|
|
18
|
+
if mode not in VALID_BACKENDS:
|
|
19
|
+
sys.stderr.write(
|
|
20
|
+
f"Invalid --backend value: {mode}. "
|
|
21
|
+
f"Use one of: {', '.join(sorted(VALID_BACKENDS))}\n"
|
|
22
|
+
)
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
return mode
|
|
25
|
+
if "--text-only" in sys.argv:
|
|
26
|
+
return "lm"
|
|
27
|
+
return "auto"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
backend_mode = parse_backend_mode()
|
|
10
31
|
|
|
11
32
|
drafter_model = None
|
|
12
33
|
if "--drafter" in sys.argv:
|
|
@@ -25,8 +46,26 @@ if "--draft-block-size" in sys.argv:
|
|
|
25
46
|
sys.exit(1)
|
|
26
47
|
|
|
27
48
|
|
|
28
|
-
def
|
|
29
|
-
|
|
49
|
+
def ensure_optiq_registered() -> None:
|
|
50
|
+
import optiq # noqa: F401 - registers vendored architectures into mlx-lm
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def create_backend(model_name: str, mode: str = "auto"):
|
|
54
|
+
if mode == "optiq":
|
|
55
|
+
ensure_optiq_registered()
|
|
56
|
+
mode = "lm"
|
|
57
|
+
|
|
58
|
+
if mode == "lm":
|
|
59
|
+
backend = MlxLmBackend()
|
|
60
|
+
backend.load(model_name)
|
|
61
|
+
return backend, "lm"
|
|
62
|
+
|
|
63
|
+
if mode == "vlm":
|
|
64
|
+
backend = MlxVlmBackend()
|
|
65
|
+
backend.load(model_name)
|
|
66
|
+
return backend, "vlm"
|
|
67
|
+
|
|
68
|
+
model_kind = detect_model_kind(model_name)
|
|
30
69
|
|
|
31
70
|
if model_kind == "vlm":
|
|
32
71
|
backend = MlxVlmBackend()
|
|
@@ -42,7 +81,7 @@ def create_backend(model_name: str, text_only: bool = False):
|
|
|
42
81
|
|
|
43
82
|
|
|
44
83
|
if __name__ == "__main__":
|
|
45
|
-
backend, model_kind = create_backend(model_name,
|
|
84
|
+
backend, model_kind = create_backend(model_name, backend_mode)
|
|
46
85
|
|
|
47
86
|
if drafter_model:
|
|
48
87
|
backend.load_drafter(drafter_model)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Streaming zip storage for MLX prompt caches."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import zipfile
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
CACHE_ENTRY_NAME = "prompt_cache.safetensors"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def save_prompt_cache_zip(
|
|
14
|
+
file_name: str,
|
|
15
|
+
cache: Any,
|
|
16
|
+
save_impl: Callable[[Any, Any], None],
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Save a prompt cache into a compressed zip member as it is produced.
|
|
19
|
+
|
|
20
|
+
``save_impl`` receives the zip member's writable stream. It must write
|
|
21
|
+
the safetensors payload to that stream instead of creating an intermediate
|
|
22
|
+
uncompressed file.
|
|
23
|
+
"""
|
|
24
|
+
with zipfile.ZipFile(
|
|
25
|
+
file_name,
|
|
26
|
+
mode="w",
|
|
27
|
+
compression=zipfile.ZIP_DEFLATED,
|
|
28
|
+
allowZip64=True,
|
|
29
|
+
) as archive:
|
|
30
|
+
with archive.open(CACHE_ENTRY_NAME, mode="w", force_zip64=True) as cache_file:
|
|
31
|
+
save_impl(cache_file, cache)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def load_prompt_cache_zip(
|
|
35
|
+
file_name: str,
|
|
36
|
+
load_impl: Callable[[Any], Any],
|
|
37
|
+
) -> Any:
|
|
38
|
+
"""Load a prompt cache from the safetensors member of a zip archive."""
|
|
39
|
+
with zipfile.ZipFile(file_name, mode="r") as archive:
|
|
40
|
+
with archive.open(CACHE_ENTRY_NAME, mode="r") as cache_file:
|
|
41
|
+
return load_impl(cache_file)
|
|
@@ -7,13 +7,29 @@ from typing import Any, Iterator
|
|
|
7
7
|
|
|
8
8
|
from mlx_lm import load as mlx_lm_load
|
|
9
9
|
from mlx_lm import stream_generate as mlx_lm_stream_generate
|
|
10
|
-
from mlx_lm.models.cache import
|
|
10
|
+
from mlx_lm.models.cache import (
|
|
11
|
+
make_prompt_cache,
|
|
12
|
+
save_prompt_cache as mlx_save_prompt_cache,
|
|
13
|
+
load_prompt_cache as mlx_load_prompt_cache,
|
|
14
|
+
trim_prompt_cache,
|
|
15
|
+
)
|
|
11
16
|
from mlx_lm.sample_utils import make_sampler
|
|
12
17
|
|
|
13
18
|
from backends.base import ModelBackend
|
|
19
|
+
from backends.cache_archive import load_prompt_cache_zip, save_prompt_cache_zip
|
|
14
20
|
from utils.token_utils import is_eod_token
|
|
15
21
|
|
|
16
22
|
|
|
23
|
+
def save_prompt_cache(file_name: str, cache: Any) -> None:
|
|
24
|
+
"""Save a prompt cache as a compressed archive without an uncompressed copy."""
|
|
25
|
+
save_prompt_cache_zip(file_name, cache, mlx_save_prompt_cache)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def load_prompt_cache(file_name: str) -> list:
|
|
29
|
+
"""Load a prompt cache from its compressed safetensors archive."""
|
|
30
|
+
return load_prompt_cache_zip(file_name, mlx_load_prompt_cache)
|
|
31
|
+
|
|
32
|
+
|
|
17
33
|
class MlxLmBackend(ModelBackend):
|
|
18
34
|
"""`mlx_lm` backend for text-only models."""
|
|
19
35
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from handlers.cache import handle_cache_prefill
|
|
2
2
|
from handlers.capabilities import handle_capabilities
|
|
3
|
-
from handlers.chat import handle_chat
|
|
4
3
|
from handlers.completion import handle_completion
|
|
5
4
|
from handlers.format_test import handle_format_test
|
|
5
|
+
from handlers.generate import handle_generate
|
|
6
|
+
from handlers.render import handle_render
|
|
6
7
|
from handlers.tokenize import handle_tokenize
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
|
-
import re
|
|
5
|
-
import sys
|
|
6
|
-
|
|
7
3
|
from backends.base import ModelBackend
|
|
8
|
-
from handlers.
|
|
4
|
+
from handlers.generate import handle_generate
|
|
9
5
|
|
|
10
6
|
|
|
11
7
|
def handle_completion(
|
|
@@ -15,25 +11,5 @@ def handle_completion(
|
|
|
15
11
|
images: list | None = None,
|
|
16
12
|
max_image_size: int = 768,
|
|
17
13
|
) -> None:
|
|
18
|
-
"""completion API
|
|
19
|
-
|
|
20
|
-
options = {}
|
|
21
|
-
|
|
22
|
-
final_options = dict(options)
|
|
23
|
-
if images:
|
|
24
|
-
final_options["max_image_size"] = max_image_size
|
|
25
|
-
if os.getenv('MLX_DEBUG'):
|
|
26
|
-
display_prompt = re.sub(r'(<\|image_pad\|>)+', '<|image_pad|>...', prompt)
|
|
27
|
-
sys.stderr.write(f"--- vlm completion (images: {len(images)}, max_size: {max_image_size})\n{display_prompt}\n")
|
|
28
|
-
elif os.getenv('MLX_DEBUG'):
|
|
29
|
-
if isinstance(prompt, list):
|
|
30
|
-
sys.stderr.write(f"--- prompt: len={len(prompt)}\n")
|
|
31
|
-
else:
|
|
32
|
-
sys.stderr.write(f"--- prompt\n{prompt}\n")
|
|
33
|
-
|
|
34
|
-
for response in backend.stream_generate(prompt, final_options, images):
|
|
35
|
-
if poll_cancel():
|
|
36
|
-
break
|
|
37
|
-
print(response.text.replace("\0", ""), end="", flush=True)
|
|
38
|
-
|
|
39
|
-
print("\n", end="\0", flush=True)
|
|
14
|
+
"""completion API(後方互換)— generate に委譲"""
|
|
15
|
+
handle_generate(backend, prompt, options, images, max_image_size)
|