# Author: Liam Grinstead # SVG tree with tier and overlay labels from lineage_tracker import get_ancestors, get_descendants def _row_positions(n: int, width: int, y: int): if n <= 0: return [] step = width // (n + 1) return [(step * (i + 1), y) for i in range(n)] def render_lineage_tree(agent_id: str, overlay_color_hue: int = 260, max_depth: int = 6) -> str: width, height = 980, 640 svg = [f""] svg.append("") svg.append(f"RFT Lineage: {agent_id}") root_x, root_y = width//2, 170 ancestors = get_ancestors(agent_id) if ancestors: pos = _row_positions(len(ancestors), width, 80) for (x,y), aid in zip(pos, ancestors): svg.append(f"") svg.append(f"{aid}") x_last, y_last = pos[-1] svg.append(f"") else: svg.append("No ancestors") svg.append(f"" "") svg.append(f"{agent_id}") levels = get_descendants(agent_id, depth=max_depth) y = 260 gap = 90 for d in range(1, max_depth + 1): nodes = levels.get(d, []) if not nodes: break pos = _row_positions(len(nodes), width, y) svg.append(f"Gen {d}") for (x, yy), item in zip(pos, nodes): hue = 40 + (15 * d) svg.append(f"" "" .replace("{h}", str(hue)) + "") label = f"{item['child_id']} · {item.get('tier','?')} · {item.get('overlay','?')}" svg.append(f"{label}") svg.append(f"") y += gap svg.append("") return "".join(svg)