diff --git a/routes/codex_routes.py b/routes/codex_routes.py
index e11965c35..52ff2949a 100644
--- a/routes/codex_routes.py
+++ b/routes/codex_routes.py
@@ -46,8 +46,12 @@ def _ssh_prefix_for_task(task: dict) -> tuple[str, str]:
shell metacharacters in ``remoteHost`` is rejected with 400 rather than
injected.
"""
- host = validate_remote_host((task.get("remoteHost") or "").strip() or None) or ""
- ssh_port = validate_ssh_port((task.get("sshPort") or "").strip() or None) or ""
+ raw_host = task.get("remoteHost")
+ raw_port = task.get("sshPort")
+ host_value = str(raw_host).strip() if raw_host is not None else None
+ port_value = str(raw_port).strip() if raw_port is not None else None
+ host = validate_remote_host(host_value or None) or ""
+ ssh_port = validate_ssh_port(port_value or None) or ""
port_flag = f"-p {ssh_port} " if ssh_port and ssh_port != "22" else ""
return host, port_flag
diff --git a/routes/cookbook_routes.py b/routes/cookbook_routes.py
index af25dd8e8..ea15a22c3 100644
--- a/routes/cookbook_routes.py
+++ b/routes/cookbook_routes.py
@@ -1284,6 +1284,11 @@ def setup_cookbook_routes() -> APIRouter:
# LOCAL execution on a native-Windows host never uses tmux (detached
# process path below), regardless of the UI-supplied platform.
local_windows = IS_WINDOWS and not remote
+ if is_windows and remote and "diffusion_server.py" in req.cmd:
+ raise HTTPException(
+ 400,
+ "Remote Windows Diffusers serving is not supported yet; use local Windows or a Linux remote server.",
+ )
if not is_windows and not local_windows and not await _binary_available("tmux", remote, req.ssh_port):
return {
diff --git a/static/js/cookbookServe.js b/static/js/cookbookServe.js
index f3b5842b2..33d56ef3c 100644
--- a/static/js/cookbookServe.js
+++ b/static/js/cookbookServe.js
@@ -116,13 +116,28 @@ function _selectedServeTarget(panel) {
: (server?.name || 'local server');
return {
host,
- port: host ? (_getPort(host) || server?.port || '') : '',
+ port: host ? (server?.port || _getPort(host) || '') : '',
+ env: server?.env || '',
venv,
platform: server?.platform || _envState.platform || '',
label,
};
}
+function _remoteWindowsDiffusersUnsupported(target) {
+ return !!(target?.host && target?.platform === 'windows');
+}
+
+function _backendChoicesForTarget(target) {
+ if (target?.platform === 'windows') {
+ if (_remoteWindowsDiffusersUnsupported(target)) return [['llamacpp','llama.cpp']];
+ return [['llamacpp','llama.cpp'],['diffusers','Diffusers']];
+ }
+ return _isMetal()
+ ? [['llamacpp','llama.cpp'],['ollama','Ollama']]
+ : [['vllm','vLLM'],['sglang','SGLang'],['llamacpp','llama.cpp'],['ollama','Ollama'],['diffusers','Diffusers']];
+}
+
async function _fetchServeRuntimePackage(panel, backend) {
const packageByBackend = {
vllm: 'vllm',
@@ -529,13 +544,14 @@ function _rerenderCachedModels() {
const ss = (_byRepo[repo] && typeof _byRepo[repo] === 'object')
? _byRepo[repo]
: (_lastUsed || (_isLegacyFlat ? _allSs : {}));
+ const _serveTarget = _selectedServeTarget();
+ const _backendChoices = _backendChoicesForTarget(_serveTarget);
+ const _allowedBackends = new Set(_backendChoices.map(([v]) => v));
const detectedBackend = _detectBackend(m).backend;
- const _allowedBackends = new Set(_isWindows()
- ? ['llamacpp', 'diffusers']
- : (_isMetal() ? ['llamacpp', 'ollama'] : ['vllm', 'sglang', 'llamacpp', 'ollama', 'diffusers']));
- const defaultBackend = (ss._forceBackend && ss.backend && _allowedBackends.has(ss.backend))
+ let defaultBackend = (ss._forceBackend && ss.backend && _allowedBackends.has(ss.backend))
? ss.backend
: detectedBackend;
+ if (!_allowedBackends.has(defaultBackend)) defaultBackend = _backendChoices[0]?.[0] || detectedBackend;
const savedMatchesBackend = !!ss._forceBackend || (ss.backend || 'vllm') === detectedBackend;
const sv = (k, def) => (ss[k] !== undefined && savedMatchesBackend) ? ss[k] : def;
const defaultTp = defaultBackend === 'llamacpp' ? '1' : sv('tp', '1');
@@ -607,12 +623,6 @@ function _rerenderCachedModels() {
}
// Row 1: Backend + Server + Env
panelHtml += `
`;
- const _backendChoices = _isWindows()
- ? [['llamacpp','llama.cpp'],['diffusers','Diffusers']]
- : _isMetal()
- // Diffusers (diffusion_server.py) is CUDA-only — omit it on Metal.
- ? [['llamacpp','llama.cpp'],['ollama','Ollama']]
- : [['vllm','vLLM'],['sglang','SGLang'],['llamacpp','llama.cpp'],['ollama','Ollama'],['diffusers','Diffusers']];
const backendOpts = _backendChoices.map(([v,l]) => ``).join('');
// Custom Backend picker — native