Skip to content

feat(desktop): visual model-architecture reader — drill-down graph + code sync + VRAM inspector (design study: LLMForge) #362

Description

@agentfleets

Summary

Proposal: a new desktop surface that renders an open-weight LLM's HuggingFace modeling_*.py source as an interactive, drill-downable block diagram, bidirectionally synced with the code pane, plus a hyperparameter inspector and a VRAM estimator.

Design reference: LLMForge's 模型架构 (model architecture) feature — screenshots below. This issue proposes borrowing its interaction and information design, re-expressed in TermiPod's existing dark token system (see "Visual-design stance" — explicitly not a palette import).

Why this fits TermiPod

TermiPod is positioning as an agent control plane and workbench. Users running/serving open-weight models through agents (SSH hosts, remote hubs) currently have no in-app way to answer: what is inside this checkpoint, and will it fit on my GPU? A visual architecture reader strengthens the workbench story: inspect a model's real source, navigate its structure, estimate deployment VRAM for the target host — without leaving the app.

Reference (LLMForge)

Three-pane workbench + config inspector:

LLMForge three-pane view and config inspector

Canvas drill-down detail (nested layer card, ×N repeat frame, tensor-shape edges, minimap, zoom rail):

LLMForge canvas drill-down

What to borrow — interaction & information design

  1. Three-pane IDE layout — left: nn.Module hierarchy tree with per-node param counts and search; center: infinite canvas; right: code viewer (代码/笔记 tabs, file breadcrumb). Clicking a graph node scrolls the code to that class; the mapping is bidirectional.
  2. Drill-down as stacked floating cards — expanding a composite module opens a child card on the canvas (own title bar: breadcrumb + ×N + param total + close), not a page zoom. Keeps parent context visible.
  3. ×N repeat-collapse — N identical decoder layers render as ONE framed container with × 61 and an aggregate badge (≈666B). The single most important readability trick for transformer graphs.
  4. Honest dataflow — tensor shapes on edges ([B, S, 7168]); residual adds drawn as ⊕ circles, not boxes; auxiliary inputs (Causal Mask, loss) as dashed-gray chips.
  5. Categorical node colors — pastel-coded by layer kind (Embedding/Norm/Attention/MLP-MoE/RoPE/Linear). See the visual-design stance below for how to adapt this to dark.
  6. Provenance badge解析质量 · 9 实证 · 1 近似 (9 verified / 1 inferred). Every number on screen declares whether it was measured or estimated. Cheap to implement, huge for trust.
  7. Floating collapsible stat chips over the canvas (架构 ≈668B, 算力·显存 1244 GiB, 图例) — glanceable totals that expand into detail.
  8. Inspector panel — sectioned key-value rows (attention/pos-enc/norm/FFN/embedding), a dense mono hyperparameter grid, a layer-schedule strip (per-layer segments colored by type), a param breakdown bar, and batch/context-length chips that recompute VRAM live.
  9. Canvas furniture — minimap, zoom rail (+/−/fit/fullscreen), layout-direction toggle.

Visual-design stance (patterns, not palette)

Compared against the desktop's current design system (design-tokens/tokens.json + 01-base-shell.css): TermiPod's dark-first, Linear/Radix-grounded language (hairline separation, shadow-less cards, single accent, AA-measured contrast) is the more modern base and should be kept. LLMForge's light surfaces, per-card drop shadows and pastel fills should not be imported.

The one sanctioned extension to the single-accent rule: categorical node colors as dark-theme tints, e.g. fill color-mix(in srgb, <hue> 12–16%, var(--surface)) + 1px hue-tinted border + hue-shifted text, sourced from existing token hues (--color-info, --color-secondary, --color-success, --color-violet, terminal cyan/magenta). Category coding is functional here (6+ layer kinds), which the single accent cannot carry; the tint approach keeps the dark elevation discipline intact.

Proposed implementation architecture

1. Ingestion → graph IR (JSON, cacheable per model+version). Two complementary routes, which is exactly what the provenance badge implies:

  • Static: parse the Python AST — class tree → module hierarchy; forward() body → dataflow edges between submodules. Yields verified structure and the code-sync source spans.
  • Numeric: infer shapes/params from config.json analytically (or optionally run a one-shot torch.fx trace / forward hooks on a dummy input for measured shapes). Anything inferred is flagged approximate.
{
  "model": "deepseek_v2", "version": "v5.13.1",
  "nodes": [{
    "id": "model.layers.0.self_attn",
    "kind": "attention",            // embedding|norm|attention|mlp|moe|rope|linear|aux
    "class": "DeepseekV2Attention",
    "attrs": { "heads": 128, "kv_heads": 128 },
    "params": 138000000, "paramsProvenance": "verified",   // or "approximate"
    "repeat": 61,
    "span": { "file": "modeling_deepseek.py", "start": 812, "end": 1040 },
    "children": [ /* nested graph */ ]
  }],
  "edges": [{ "from": "", "to": "", "shape": "[B,S,7168]", "kind": "residual|data|aux" }]
}

2. LayoutELK (elkjs, layered/Sugiyama): proper support for compound/nested graphs, ports, orthogonal edge routing. (@hpcc-js/wasm-graphviz is already shipped and is an acceptable M1 fallback, but it handles compound nesting poorly.) Expanding a card re-layouts only that subgraph.

3. CanvasReact Flow (XYFlow), new dep (~50 kB): custom node components, subflows/containers, minimap, zoom controls and edge labels out of the box. Custom Canvas/WebGL only if node counts exceed ~1–2k.

4. Code paneCodeMirror (already a dependency), read-only, with sourceSpan ranges for node↔code highlighting.

5. Inspector + VRAM estimator — pure TypeScript arithmetic from config.json per architecture family (MLA/GQA attention, dense/MoE FFN, embeddings): params per layer type; VRAM = weights (params × dtype bytes) + KV cache (layers × kv-heads × head-dim × ctx × batch × bytes) + activation estimate. Config profiles (默认配置 vs overrides) recompute client-side, instant.

Execution location: analysis is a small Python worker (AST extraction, stdlib-only for M1) runnable over SSH on the agent host or as a hub-side job; the IR JSON is cached per (model, version) so re-opens are instant.

Phasing

  • M1 — structure: AST module tree (left pane) + ELK-laid-out top-level graph on a React Flow canvas, read-only, one local model dir. Provenance flag on every number from day one.
  • M2 — depth: drill-down stacked cards, ×N repeat-collapse, node↔code bidirectional sync, tensor-shape edge labels.
  • M3 — inspector: config inspector panel, layer-schedule strip, param breakdown, batch/ctx VRAM estimator with config profiles.

Open questions for the maintainer

  1. Analysis runtime: ship the Python AST worker for SSH hosts only, or also hub-side for browser-build users?
  2. React Flow as a new dependency vs. extending the existing CanvasEditor stack? (React Flow's subflow/minimap primitives map 1:1 to the drill-down design; CanvasEditor is a document canvas, not a graph renderer.)
  3. Model-family coverage order — deepseek / llama / qwen first (single modeling_*.py files, well-structured), MoE families later?
  4. Where does the surface live in the IA: a new surface next to Read, or a mode of the Library?

Non-goals

  • No model execution/training integration, no live activation inspection (M-beyond).
  • Not a general Netron replacement — scoped to HF modeling_*.py source reading.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions