Files
llama-watch/src/lib/runtime.ts
T

76 lines
2.1 KiB
TypeScript

import { EventFeed } from "./event-feed";
import { InflightTracker } from "./inflight-tracker";
import { MetricsPoller } from "./metrics-poller";
import { StatsCache } from "./stats-cache";
import { type UsageStats } from "./stats";
import { type LlamaSwapConfig } from "./util";
class Runtime {
readonly tracker = new InflightTracker();
offline = true;
private cfg?: LlamaSwapConfig;
private feed?: EventFeed;
private poller?: MetricsPoller;
private statsCache?: StatsCache;
private listeners = new Set<() => void>();
ensureConnections(cfg: LlamaSwapConfig): void {
const changed = !this.cfg || this.cfg.baseUrl !== cfg.baseUrl || this.cfg.apiKey !== cfg.apiKey;
if (changed) {
this.feed?.stop();
this.poller?.stop();
this.feed = undefined;
this.poller = undefined;
this.statsCache?.setConfig(cfg);
this.cfg = cfg;
}
if (!this.feed) {
this.feed = new EventFeed(cfg, (ev) => {
this.tracker.apply(ev);
if (ev.type === "activity") this.statsCache?.scheduleRefresh();
this.emit();
});
this.feed.setStatusHandler((connected) => {
this.offline = !connected;
this.emit();
});
this.feed.start();
}
if (!this.poller) {
this.poller = new MetricsPoller(cfg);
this.poller.on(() => this.emit());
this.poller.start();
}
if (!this.statsCache) {
this.statsCache = new StatsCache(cfg);
this.statsCache.onChange(() => this.emit());
}
}
get pollerInstance(): MetricsPoller | undefined {
return this.poller;
}
getStats(modelId: string): UsageStats | undefined {
return this.statsCache?.get(modelId);
}
watchStats(modelId: string): () => void {
this.statsCache?.register(modelId);
return () => this.statsCache?.unregister(modelId);
}
subscribe(listener: () => void): () => void {
this.listeners.add(listener);
return () => {
this.listeners.delete(listener);
};
}
private emit(): void {
for (const listener of this.listeners) listener();
}
}
export const runtime = new Runtime();