(
router: ModelRouter,
config: QodexConfig,
opts: { timeoutMs?: number } = {},
)
| 22 | * doesn't auto-unload while idle. |
| 23 | */ |
| 24 | export async function warmModel( |
| 25 | router: ModelRouter, |
| 26 | config: QodexConfig, |
| 27 | opts: { timeoutMs?: number } = {}, |
| 28 | ): Promise<{ warmed: boolean; reason: string }> { |
| 29 | try { |
| 30 | const modelId = config.defaults.model; |
| 31 | const resolved = router.resolveModel(modelId); |
| 32 | if (!resolved) return { warmed: false, reason: 'model-not-resolved' }; |
| 33 | if (!resolved.provider.isLocal) return { warmed: false, reason: 'cloud-skip' }; |
| 34 | |
| 35 | const timeoutMs = opts.timeoutMs ?? 120_000; |
| 36 | const ac = new AbortController(); |
| 37 | const timer = setTimeout(() => ac.abort(), timeoutMs); |
| 38 | try { |
| 39 | const gen = resolved.provider.complete({ |
| 40 | model: resolved.resolvedId, |
| 41 | messages: [{ role: 'user', content: 'ping' }], |
| 42 | maxTokens: 1, |
| 43 | temperature: 0, |
| 44 | signal: ac.signal, |
| 45 | } as any); |
| 46 | // Draining the first event is enough — the server loads the model before it streams. |
| 47 | for await (const _ev of gen) break; |
| 48 | logger.info('Model warmed', { model: resolved.resolvedId }); |
| 49 | return { warmed: true, reason: 'ok' }; |
| 50 | } finally { |
| 51 | clearTimeout(timer); |
| 52 | } |
| 53 | } catch (e) { |
| 54 | logger.warn('Model warm-up skipped', { err: (e as Error)?.message }); |
| 55 | return { warmed: false, reason: 'error' }; |
| 56 | } |
| 57 | } |
no test coverage detected