feat: decode activity SSE events and expose tracker total

This commit is contained in:
c4ch3c4d3
2026-08-14 12:53:40 -06:00
parent a03278645d
commit 4727bdcf46
4 changed files with 30 additions and 0 deletions
+6
View File
@@ -8,6 +8,12 @@ export function decodeEvent(msg: SseMessage): FeedEvent | null {
if (!outer.data) return null; if (!outer.data) return null;
const inner = JSON.parse(outer.data) as Record<string, unknown>; const inner = JSON.parse(outer.data) as Record<string, unknown>;
if (outer.type === "activity") {
const id = typeof inner.id === "number" ? inner.id : Number.NaN;
if (Number.isFinite(id)) return { type: "activity", id };
return null;
}
if (outer.type === "inflight") { if (outer.type === "inflight") {
const operation = inner.operation as string; const operation = inner.operation as string;
if (operation === "remove") { if (operation === "remove") {
+5
View File
@@ -15,6 +15,7 @@ export interface ModelState {
export type FeedEvent = export type FeedEvent =
| { type: "inflight"; operation: "snapshot" | "add"; requests: InflightRequest[] } | { type: "inflight"; operation: "snapshot" | "add"; requests: InflightRequest[] }
| { type: "inflight"; operation: "remove"; id: string } | { type: "inflight"; operation: "remove"; id: string }
| { type: "activity"; id: number }
| { type: "modelStatus"; models: ModelState[] }; | { type: "modelStatus"; models: ModelState[] };
export type ModelRuntimeState = "stopped" | "loading" | "ready"; export type ModelRuntimeState = "stopped" | "loading" | "ready";
@@ -44,6 +45,10 @@ export class InflightTracker {
return n; return n;
} }
total(): number {
return this.requests.size;
}
state(modelId: string): ModelRuntimeState | undefined { state(modelId: string): ModelRuntimeState | undefined {
return this.states.get(modelId); return this.states.get(modelId);
} }
+9
View File
@@ -117,3 +117,12 @@ test("decodeEvent handles inflight with a non-array requests field and no reques
assert.deepEqual(ev.requests, []); assert.deepEqual(ev.requests, []);
} }
}); });
test("decodeEvent parses an activity event with an id", () => {
const msg: SseMessage = {
event: "message",
data: JSON.stringify({ type: "activity", data: JSON.stringify({ id: 817 }) }),
};
const ev = decodeEvent(msg);
assert.deepEqual(ev, { type: "activity", id: 817 });
});
+10
View File
@@ -63,3 +63,13 @@ test("modelStatus normalizes states", () => {
assert.equal(tracker.state("D"), "stopped"); assert.equal(tracker.state("D"), "stopped");
assert.equal(tracker.state("missing"), undefined); assert.equal(tracker.state("missing"), undefined);
}); });
test("total sums in-flight requests across all models", () => {
const tracker = new InflightTracker();
assert.equal(tracker.total(), 0);
tracker.apply({ type: "inflight", operation: "add", requests: [{ model: "A", id: "1" }, { model: "B", id: "2" }] });
tracker.apply({ type: "inflight", operation: "add", requests: [{ model: "A", id: "3" }] });
assert.equal(tracker.total(), 3);
tracker.apply({ type: "inflight", operation: "remove", id: "1" });
assert.equal(tracker.total(), 2);
});