diff --git a/features/messaging/ios/Package.swift b/features/messaging/ios/Package.swift index d0867c1fa..ed1107aa6 100644 --- a/features/messaging/ios/Package.swift +++ b/features/messaging/ios/Package.swift @@ -24,7 +24,7 @@ let package = Package( .package(url: "https://forge.nasty.sh/lilith/swift-buttons.git", from: "1.0.0"), .package(url: "https://forge.nasty.sh/lilith/swift-forms.git", from: "1.0.0"), .package(url: "https://forge.nasty.sh/lilith/swift-feedback.git", from: "1.0.0"), - .package(url: "https://forge.nasty.sh/lilith/swift-layout.git", from: "1.0.3"), + .package(url: "https://forge.nasty.sh/lilith/swift-layout.git", from: "1.0.5"), // Messaging packages .package(url: "https://forge.nasty.sh/lilith/swift-chat-core.git", from: "1.0.0"), .package(url: "https://forge.nasty.sh/lilith/swift-domain-models.git", from: "1.0.0"), diff --git a/features/messaging/ios/project.yml b/features/messaging/ios/project.yml index f57333392..48c7fe1e0 100644 --- a/features/messaging/ios/project.yml +++ b/features/messaging/ios/project.yml @@ -34,7 +34,7 @@ packages: from: "1.0.0" swift-layout: url: https://forge.nasty.sh/lilith/swift-layout.git - from: "1.0.3" + from: "1.0.5" swift-chat-core: url: https://forge.nasty.sh/lilith/swift-chat-core.git from: "1.0.0" diff --git a/tools/talent-scout/src/api/captcha-solver-controller.ts b/tools/talent-scout/src/api/captcha-solver-controller.ts index 3ec3bcd7e..7dc174cf0 100644 --- a/tools/talent-scout/src/api/captcha-solver-controller.ts +++ b/tools/talent-scout/src/api/captcha-solver-controller.ts @@ -10,6 +10,17 @@ import type { CaptchaSolverManager } from '../services/captcha-solver'; import type { Request, Response } from 'express'; import type { DataSource } from 'typeorm'; +async function probeExternalHealth(port: number): Promise { + try { + const res = await fetch(`http://127.0.0.1:${port}/health`, { + signal: AbortSignal.timeout(2000), + }); + return res.ok; + } catch { + return false; + } +} + interface CaptchaSolverDeps { solverManager: CaptchaSolverManager | null; dataSource: DataSource; @@ -22,26 +33,32 @@ export function createCaptchaSolverRouter(deps: CaptchaSolverDeps): Router { /** * GET /api/controlpanel/captcha/solver/status — CAPTCHA solver process status + pool info */ - router.get('/api/controlpanel/captcha/solver/status', (_req: Request, res: Response) => { + router.get('/api/controlpanel/captcha/solver/status', async (_req: Request, res: Response) => { if (!solverManager) { res.status(503).json({ error: 'CAPTCHA solver manager not available' }); return; } - const status = solverManager.getStatus(); + let status = solverManager.getStatus(); const pid = solverManager.getPid(); const startedAt = solverManager.getStartedAt(); const pool = solverManager.getPoolStatus(); - const lastError = solverManager.getLastError(); + // When workers are managed externally, probe the health endpoint directly + if (process.env.EXTERNAL_WORKERS && status === 'inactive') { + const port = Number(process.env.CAPTCHA_PORT) || 3099; + const healthy = await probeExternalHealth(port); + if (healthy) status = 'active'; + } + res.json({ data: { service: 'captcha-solver', active: status, description: status === 'error' && lastError ? lastError - : `CAPTCHA ML solver (port 3099)`, + : `CAPTCHA ML solver (port ${Number(process.env.CAPTCHA_PORT) || 3099})`, since: startedAt ? new Date(startedAt).toISOString() : '', pid: pid ? String(pid) : null, memory: null, diff --git a/tools/talent-scout/src/api/llm-service-controller.ts b/tools/talent-scout/src/api/llm-service-controller.ts index 0e8710d70..2a4b58ba8 100644 --- a/tools/talent-scout/src/api/llm-service-controller.ts +++ b/tools/talent-scout/src/api/llm-service-controller.ts @@ -11,6 +11,17 @@ import type { LlmServiceManager } from '../services/llm-service'; import type { ExpertId } from '../experts/types'; import type { Request, Response } from 'express'; +async function probeExternalHealth(port: number): Promise { + try { + const res = await fetch(`http://127.0.0.1:${port}/health`, { + signal: AbortSignal.timeout(2000), + }); + return res.ok; + } catch { + return false; + } +} + interface LlmServiceDeps { llmServiceManager: LlmServiceManager | null; } @@ -47,25 +58,34 @@ export function createLlmServiceRouter(deps: LlmServiceDeps): Router { /** * GET /api/controlpanel/llm/status — LLM service process status */ - router.get('/api/controlpanel/llm/status', (_req: Request, res: Response) => { + router.get('/api/controlpanel/llm/status', async (_req: Request, res: Response) => { if (!llmServiceManager) { res.status(503).json({ error: 'LLM service manager not available' }); return; } - const status = llmServiceManager.getStatus(); + let status = llmServiceManager.getStatus(); const pid = llmServiceManager.getPid(); const startedAt = llmServiceManager.getStartedAt(); const lastError = llmServiceManager.getLastError(); const pool = llmServiceManager.getPoolStatus(); + // When workers are managed externally, probe the health endpoint directly + if (process.env.EXTERNAL_WORKERS && status === 'inactive') { + const port = Number(process.env.LLM_PORT) || 8100; + const healthy = await probeExternalHealth(port); + if (healthy) status = 'active'; + } + + const port = Number(process.env.LLM_PORT) || llmServiceManager.getPort(); + res.json({ data: { service: 'llm-service', active: status, description: status === 'error' && lastError ? lastError - : `LLM inference (port ${llmServiceManager.getPort()})`, + : `LLM inference (port ${port})`, since: startedAt ? new Date(startedAt).toISOString() : '', pid: pid ? String(pid) : null, memory: null,