llama-swap emits inflight events with operation 'upsert' (a single request, re-emitted as elapsed_ms updates) and id-only 'remove' events. The decoder ignored 'upsert' and dropped every id-only remove, so the tracker only ever reflected the connect-time snapshot and the count got stuck (e.g. at '1'). The tracker now keys in-flight state by request id (snapshot/add replace by id; remove deletes by id), and the decoder normalizes 'upsert' to 'add' and extracts the id from bare removes.
57 lines
1.6 KiB
TypeScript
57 lines
1.6 KiB
TypeScript
export interface InflightRequest {
|
|
id?: string;
|
|
model: string;
|
|
req_path?: string;
|
|
method?: string;
|
|
timestamp?: string;
|
|
elapsed_ms?: number;
|
|
}
|
|
|
|
export interface ModelState {
|
|
id: string;
|
|
state: string;
|
|
}
|
|
|
|
export type FeedEvent =
|
|
| { type: "inflight"; operation: "snapshot" | "add"; requests: InflightRequest[] }
|
|
| { type: "inflight"; operation: "remove"; id: string }
|
|
| { type: "modelStatus"; models: ModelState[] };
|
|
|
|
export type ModelRuntimeState = "stopped" | "loading" | "ready";
|
|
|
|
export class InflightTracker {
|
|
private requests = new Map<string, string>();
|
|
private states = new Map<string, ModelRuntimeState>();
|
|
|
|
apply(event: FeedEvent): void {
|
|
if (event.type === "inflight") {
|
|
if (event.operation === "snapshot") {
|
|
this.requests = new Map<string, string>();
|
|
for (const r of event.requests) if (r.id) this.requests.set(r.id, r.model);
|
|
} else if (event.operation === "add") {
|
|
for (const r of event.requests) if (r.id) this.requests.set(r.id, r.model);
|
|
} else if (event.operation === "remove") {
|
|
this.requests.delete(event.id);
|
|
}
|
|
} else if (event.type === "modelStatus") {
|
|
for (const m of event.models) this.states.set(m.id, normalizeState(m.state));
|
|
}
|
|
}
|
|
|
|
count(modelId: string): number {
|
|
let n = 0;
|
|
for (const model of this.requests.values()) if (model === modelId) n++;
|
|
return n;
|
|
}
|
|
|
|
state(modelId: string): ModelRuntimeState | undefined {
|
|
return this.states.get(modelId);
|
|
}
|
|
}
|
|
|
|
function normalizeState(state: string): ModelRuntimeState {
|
|
if (state === "ready") return "ready";
|
|
if (state === "loading") return "loading";
|
|
return "stopped";
|
|
}
|