import type { OllamaEnsureResult, ThtRunner } from "../tht/tht-runner.js"; import type { PrincipalContext } from "../auth/principal.js"; interface ReadyEntry { expiresAt: number; result: OllamaEnsureResult; } /** * Deduplicates embedding readiness checks and keeps only short-lived successes. * Failures are deliberately not cached so a submit can retry after a transient outage. */ export class ReadinessManager { private inFlight = new Map>(); private ready = new Map(); constructor( private tht: ThtRunner, private timeoutSec: number, private ttlMs = 60_000, private now: () => number = Date.now, ) {} ensure(workspace = "", principal?: PrincipalContext): Promise { const key = `${principal?.issuer ?? ""}\0${principal?.subject ?? ""}\0${workspace}`; const cached = this.ready.get(key); if (cached && cached.expiresAt > this.now()) return Promise.resolve(cached.result); if (cached) this.ready.delete(key); const current = this.inFlight.get(key); if (current) return current; const runner = principal && typeof (this.tht as any).withPrincipal === "function" ? this.tht.withPrincipal(principal) : this.tht; const pending = runner.ollamaEnsure(workspace, this.timeoutSec) .then((result) => { if (result.ok) { this.ready.set(key, { result, expiresAt: this.now() + this.ttlMs }); } return result; }) .finally(() => { if (this.inFlight.get(key) === pending) this.inFlight.delete(key); }); this.inFlight.set(key, pending); return pending; } }