mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-12 17:22:38 +02:00
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import type { TimelineGroup, TimelineItem } from "./types";
|
|
|
|
/**
|
|
* Group delegated child items under their owning ``task`` parent.
|
|
*
|
|
* Backend invariant: ``metadata.spanId`` is set only while a ``task``
|
|
* tool is open, so every non-task item with ``spanId = X`` shares it
|
|
* with the ``task`` that owns the span. We promote that task to the
|
|
* group header.
|
|
*
|
|
* The owner-missing branch defends against the live-resume window
|
|
* where the OLD ``task`` wrapper can be superseded while its
|
|
* children briefly survive — without it, grouping would promote
|
|
* the first orphan child to parent and visually nest its siblings
|
|
* under it.
|
|
*/
|
|
export function groupItems(items: readonly TimelineItem[]): TimelineGroup[] {
|
|
const spanOwners = new Set<string>();
|
|
for (const item of items) {
|
|
if (item.kind === "tool-call" && item.toolName === "task" && item.spanId) {
|
|
spanOwners.add(item.spanId);
|
|
}
|
|
}
|
|
|
|
const groups: TimelineGroup[] = [];
|
|
const spanParent = new Map<string, TimelineGroup>();
|
|
|
|
for (const item of items) {
|
|
const sid = item.spanId;
|
|
if (!sid || !spanOwners.has(sid)) {
|
|
groups.push({ parent: item, children: [] });
|
|
continue;
|
|
}
|
|
|
|
const existing = spanParent.get(sid);
|
|
if (existing) {
|
|
existing.children.push(item);
|
|
continue;
|
|
}
|
|
|
|
const group: TimelineGroup = { parent: item, children: [] };
|
|
groups.push(group);
|
|
spanParent.set(sid, group);
|
|
}
|
|
|
|
return groups;
|
|
}
|