Add LoRA stacks with per-item strengths and named video/image generation presets so setups survive reload without mixing Klein onto MiniMax. Keep LTX Pink Cherry and xAIGen LoRAs on xAIGen, and run Recommend on Beast.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -187,7 +187,7 @@ async function ensureUnlocked(onStatus: StatusFn) {
|
||||
|
||||
onStatus({
|
||||
state: 'starting',
|
||||
message: 'Image ComfyUI is offline. Starting the sidecar instance...',
|
||||
message: 'Image ComfyUI is offline. Starting the Beast instance...',
|
||||
host,
|
||||
processRunning: Boolean(remote?.process)
|
||||
})
|
||||
@@ -195,7 +195,7 @@ async function ensureUnlocked(onStatus: StatusFn) {
|
||||
if (!started.started && started.reason === 'no-launcher') {
|
||||
throw createError({
|
||||
statusCode: 503,
|
||||
statusMessage: 'Image ComfyUI is offline and the sidecar host agent did not start it. Confirm the agent on 192.168.77.101:8199 is running.'
|
||||
statusMessage: 'Image ComfyUI is offline and the Beast host agent did not start it. Confirm COMFY_CONTROL_URL is running.'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -230,111 +230,26 @@ export function ensureImageComfyReady(onStatus: StatusFn = () => undefined) {
|
||||
}
|
||||
|
||||
let sidecarGate: Promise<unknown> = Promise.resolve()
|
||||
let sidecarLastStartAt = 0
|
||||
|
||||
function sidecarControlSettings() {
|
||||
const config = useRuntimeConfig()
|
||||
return {
|
||||
host: getSidecarImageHost(),
|
||||
controlUrl: String(config.imageComfyControlUrl || process.env.IMAGE_COMFY_CONTROL_URL || '').replace(/\/$/, ''),
|
||||
controlToken: String(config.imageComfyControlToken || process.env.IMAGE_COMFY_CONTROL_TOKEN || ''),
|
||||
healthTimeoutMs: 2500,
|
||||
startTimeoutMs: Number(process.env.IMAGE_COMFY_START_TIMEOUT_MS || 180_000)
|
||||
}
|
||||
}
|
||||
|
||||
async function sidecarControlRequest(path: string, method = 'GET') {
|
||||
const { controlUrl, controlToken } = sidecarControlSettings()
|
||||
if (!controlUrl) return null
|
||||
try {
|
||||
const res = await fetch(`${controlUrl}${path}`, {
|
||||
method,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
...(controlToken ? { Authorization: `Bearer ${controlToken}` } : {})
|
||||
},
|
||||
signal: AbortSignal.timeout(5000)
|
||||
})
|
||||
if (!res.ok) return { ok: false, status: res.status }
|
||||
return await res.json() as {
|
||||
ok?: boolean
|
||||
http?: boolean
|
||||
process?: boolean
|
||||
started?: boolean
|
||||
already?: boolean
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function startSidecarComfy() {
|
||||
const now = Date.now()
|
||||
if (now - sidecarLastStartAt < 15_000) {
|
||||
log('sidecar-start-skipped', { reason: 'recent-start' })
|
||||
return { started: false, reason: 'recent-start' as const }
|
||||
}
|
||||
sidecarLastStartAt = now
|
||||
const remote = await sidecarControlRequest('/start', 'POST')
|
||||
if (remote?.ok || remote?.started) {
|
||||
log('sidecar-start-remote', {})
|
||||
return { started: true, reason: 'remote' as const }
|
||||
}
|
||||
return { started: false, reason: 'no-launcher' as const }
|
||||
}
|
||||
|
||||
async function ensureSidecarUnlocked(onStatus: StatusFn) {
|
||||
const cfg = sidecarControlSettings()
|
||||
const host = cfg.host
|
||||
const host = getSidecarImageHost()
|
||||
if (!host) {
|
||||
throw createError({
|
||||
statusCode: 503,
|
||||
statusMessage: 'Sidecar Qwen VL is not configured. Set IMAGE_COMFY_HOST or IMAGE_COMFY_FALLBACK_HOST.'
|
||||
statusMessage: 'Qwen VL is not configured. Set COMFY_HOST or IMAGE_COMFY_HOST to Beast.'
|
||||
})
|
||||
}
|
||||
|
||||
onStatus({ state: 'offline', message: 'Checking Sidecar Qwen VL…', host, box: 'sidecar' })
|
||||
const health = await checkImageComfyHttp(cfg.healthTimeoutMs, host)
|
||||
onStatus({ state: 'offline', message: 'Checking Beast Qwen VL…', host, box: 'beast' })
|
||||
const health = await checkImageComfyHttp(2500, host)
|
||||
if (health.ok) {
|
||||
onStatus({ state: 'online', message: 'Sidecar Qwen VL online', host, box: 'sidecar' })
|
||||
onStatus({ state: 'online', message: 'Beast Qwen VL online', host, box: 'beast' })
|
||||
return
|
||||
}
|
||||
|
||||
onStatus({
|
||||
state: 'starting',
|
||||
message: 'Sidecar is offline. Starting Qwen VL on 192.168.77.101…',
|
||||
host,
|
||||
box: 'sidecar'
|
||||
})
|
||||
const started = await startSidecarComfy()
|
||||
if (!started.started && started.reason === 'no-launcher') {
|
||||
throw createError({
|
||||
statusCode: 503,
|
||||
statusMessage: 'Sidecar is offline and the host agent did not start it. Confirm the agent on 192.168.77.101:8199 is running.'
|
||||
})
|
||||
}
|
||||
|
||||
const deadline = Date.now() + cfg.startTimeoutMs
|
||||
let attempt = 0
|
||||
while (Date.now() < deadline) {
|
||||
attempt += 1
|
||||
onStatus({
|
||||
state: 'starting',
|
||||
message: `Starting Sidecar Qwen VL… waiting for Comfy (${attempt})`,
|
||||
host,
|
||||
box: 'sidecar'
|
||||
})
|
||||
const next = await checkImageComfyHttp(cfg.healthTimeoutMs, host)
|
||||
if (next.ok) {
|
||||
onStatus({ state: 'online', message: 'Sidecar Qwen VL online', host, box: 'sidecar', processRunning: true })
|
||||
return
|
||||
}
|
||||
await sleep(2000)
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 503,
|
||||
statusMessage: 'Started Sidecar Qwen VL but it never answered. The 101 box can take a couple of minutes to load after a cold boot.'
|
||||
statusMessage: `Beast ComfyUI is offline (${host}). Recommend needs Qwen VL on that instance and will not start a sidecar.`
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user