Files
amosblomqvist 4001c3465b Graph view: unique pill keys for chunk jobs (second duplicate-key consumer)
The graph page's pipeline pills keyed rows by run.chatId — the source id,
shared by every chunk job of a fan-out (the dock got the same fix in
8f66f47; this consumer was missed). /api/graph/status rows now carry an
id (the registry job key: source id, or 'src#i'), and the pills key by
it. chatId stays the SOURCE id — the reveal refetch and per-run cost
refresh track chatId SETS, which dedupe naturally and fire when the
source's LAST row leaves the feed.
2026-09-29 01:26:23 +03:00

37 lines
1.6 KiB
TypeScript

/**
* GET /api/graph/status — the in-flight background extraction runs
* (vision §1: the pipeline status must be visible on the home graph).
* Thin transport over the pipeline's module-level registry: phase
* (queued / extracting / waiting / auditing / merging) per job, oldest
* first — a multi-chunk source shows one row PER CHUNK ("· i/N" suffix,
* per-chunk jobs, owner 2026-09-28). Titles joined from the chat store;
* a missing chat record still reports the run.
*/
import { chatStore, extractionStatuses } from "@/src/server";
export const dynamic = "force-dynamic";
export async function GET() {
const runs = extractionStatuses().map((run) => ({
// Unique row id (the registry job key: source id, or "src#i" for
// chunk jobs) — one source's rows share chatId, and React keys on
// it would collide. chatId stays the SOURCE id: reveal/cost
// tracking in the view is source-scoped by design.
id: run.part ? `${run.chatId}#${run.part.i}` : run.chatId,
chatId: run.chatId,
// The run's own label (the file path for notes imports) wins; chat
// runs fall back to the chat store's title. Chunk jobs append their
// part ("· 2/5") — one row per chunk of the fan-out.
title:
(run.label ?? chatStore.getChat(run.chatId)?.title ?? run.chatId) +
(run.part ? ` · ${run.part.i}/${run.part.n}` : ""),
phase: run.phase,
startedAt: run.startedAt,
// Live per-stage usage (the money channel): model + per-step CallUsage,
// accumulated as steps bill. Cost and context-window folds are the
// consumer's (core/prices.ts helpers — nothing stores dollars).
usage: run.usage,
}));
return Response.json({ runs });
}