This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
export interface DelegateRun {
|
||||
delegateRunId: string;
|
||||
parentRunId: string | null;
|
||||
description: string;
|
||||
depth: number;
|
||||
status: 'success' | 'aborted' | 'needs_user_input' | 'running';
|
||||
startTs: string;
|
||||
endTs: string | null;
|
||||
eventCount: number;
|
||||
toolCalls: number;
|
||||
}
|
||||
|
||||
export interface DelegateRunNode extends DelegateRun {
|
||||
children: DelegateRunNode[];
|
||||
}
|
||||
|
||||
/** delegate run の status に対応する i18n ラベルキーと Tailwind 色クラス。 */
|
||||
export function delegateStatusBadge(
|
||||
status: DelegateRun['status'],
|
||||
): { labelKey: string; cls: string } {
|
||||
switch (status) {
|
||||
case 'success': return { labelKey: 'subtasks.delegateStatus.success', cls: 'bg-emerald-100 text-emerald-800' };
|
||||
case 'aborted': return { labelKey: 'subtasks.delegateStatus.aborted', cls: 'bg-red-100 text-red-800' };
|
||||
case 'needs_user_input': return { labelKey: 'subtasks.delegateStatus.needs_user_input', cls: 'bg-amber-100 text-amber-800' };
|
||||
default: return { labelKey: 'subtasks.delegateStatus.running', cls: 'bg-blue-100 text-blue-800' };
|
||||
}
|
||||
}
|
||||
|
||||
/** endTs があればそこまで、無ければ now までの経過。clock skew で負にならないようガード。 */
|
||||
export function formatElapsed(startTs: string, endTs: string | null, now: number): string {
|
||||
const end = endTs ? new Date(endTs).getTime() : now;
|
||||
const ms = Math.max(0, end - new Date(startTs).getTime());
|
||||
if (ms < 1000) return `${ms}ms`;
|
||||
if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
|
||||
return `${Math.floor(ms / 60_000)}m${Math.floor((ms % 60_000) / 1000)}s`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a tree from a flat list of DelegateRun records.
|
||||
* Runs whose parentRunId is null, or whose parent is not in the set,
|
||||
* are treated as roots (orphan fallback — no data loss).
|
||||
*/
|
||||
export function buildDelegateRunTree(runs: DelegateRun[]): DelegateRunNode[] {
|
||||
const nodes = new Map<string, DelegateRunNode>();
|
||||
for (const r of runs) {
|
||||
nodes.set(r.delegateRunId, { ...r, children: [] });
|
||||
}
|
||||
const roots: DelegateRunNode[] = [];
|
||||
for (const node of nodes.values()) {
|
||||
const parent = node.parentRunId ? nodes.get(node.parentRunId) : undefined;
|
||||
if (parent) {
|
||||
parent.children.push(node);
|
||||
} else {
|
||||
roots.push(node);
|
||||
}
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
Reference in New Issue
Block a user