Skip to content

Commit 9df6cb2

Browse files
fix(drawio): add string resilience and top-level relationship handling in _class_diagram
1 parent b650743 commit 9df6cb2

1 file changed

Lines changed: 55 additions & 11 deletions

File tree

‎langgraph_engine/diagrams/drawio/converter.py‎

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,14 @@ def _class_diagram(self, data, nid):
168168
id_map = {} # class name -> cell id
169169

170170
for idx, cls in enumerate(classes[:40]):
171+
if isinstance(cls, str):
172+
cls = {"name": cls}
173+
elif not isinstance(cls, dict):
174+
continue
175+
171176
name = cls.get("name", "Class%d" % idx)
172177
attrs = cls.get("attributes", [])[:10]
173178
meths = cls.get("methods", [])[:12]
174-
cls.get("bases", [])
175179
is_iface = cls.get("is_interface", "interface" in name.lower())
176180
is_abst = cls.get("is_abstract", False)
177181

@@ -204,10 +208,13 @@ def _class_diagram(self, data, nid):
204208
# Attributes section (child of container)
205209
attr_lines = []
206210
for a in attrs:
207-
vis = a.get("visibility", "+")
208-
hint = a.get("type_hint", "")
209-
t = (": " + hint) if hint else ""
210-
attr_lines.append("%s %s%s" % (vis, a["name"], t))
211+
if isinstance(a, dict):
212+
vis = a.get("visibility", "+")
213+
hint = a.get("type_hint", "")
214+
t = (": " + hint) if hint else ""
215+
attr_lines.append("%s %s%s" % (vis, a.get("name", ""), t))
216+
else:
217+
attr_lines.append(str(a))
211218
attr_text = "
".join(attr_lines) if attr_lines else " "
212219
cells.append(_vertex_child(nid(), attr_text, S_CLASS_ROW, 0, HDR_H, BOX_W, attr_h, cid))
213220

@@ -217,15 +224,21 @@ def _class_diagram(self, data, nid):
217224
# Methods section
218225
meth_lines = []
219226
for m in meths:
220-
vis = m.get("visibility", "+")
221-
params = ", ".join(m.get("params", [])[:4])
222-
ret = (": " + m["return_type"]) if m.get("return_type") else ""
223-
meth_lines.append("%s %s(%s)%s" % (vis, m["name"], params, ret))
227+
if isinstance(m, dict):
228+
vis = m.get("visibility", "+")
229+
params = ", ".join(str(p) for p in m.get("params", [])[:4])
230+
ret = (": " + m["return_type"]) if m.get("return_type") else ""
231+
mname = m.get("name", "method")
232+
meth_lines.append("%s %s(%s)%s" % (vis, mname, params, ret))
233+
else:
234+
meth_lines.append(str(m))
224235
meth_text = "
".join(meth_lines) if meth_lines else " "
225236
cells.append(_vertex_child(nid(), meth_text, S_CLASS_ROW, 0, HDR_H + attr_h + DIV_H, BOX_W, meth_h, cid))
226237

227-
# Relationships
238+
# Relationships embedded in classes
228239
for cls in classes[:40]:
240+
if not isinstance(cls, dict):
241+
continue
229242
src_id = id_map.get(cls.get("name", ""))
230243
if not src_id:
231244
continue
@@ -236,7 +249,10 @@ def _class_diagram(self, data, nid):
236249
cells.append(_edge(nid(), "", S_INHERIT, src_id, tgt_id))
237250
# Explicit relationships list
238251
for rel in cls.get("relationships", [])[:4]:
239-
tgt_id = id_map.get(rel.get("target", ""))
252+
if not isinstance(rel, dict):
253+
continue
254+
tgt_n = rel.get("to", rel.get("target", ""))
255+
tgt_id = id_map.get(tgt_n)
240256
if not tgt_id:
241257
continue
242258
rtype = rel.get("type", "associate").lower()
@@ -251,6 +267,34 @@ def _class_diagram(self, data, nid):
251267
else:
252268
cells.append(_edge(nid(), "", S_ASSOCIATE, src_id, tgt_id))
253269

270+
# Top-level relationships
271+
top_rels = data.get("relationships") or data.get("edges") or data.get("links") or data.get("dependencies") or []
272+
for rel in top_rels[:20]:
273+
if isinstance(rel, (list, tuple)) and len(rel) >= 2:
274+
src_n, tgt_n = str(rel[0]), str(rel[1])
275+
rtype = str(rel[2]).lower() if len(rel) > 2 else "associate"
276+
elif isinstance(rel, dict):
277+
src_n = rel.get("from", rel.get("source", ""))
278+
tgt_n = rel.get("to", rel.get("target", ""))
279+
rtype = rel.get("type", rel.get("label", "associate")).lower()
280+
else:
281+
continue
282+
src_id = id_map.get(src_n)
283+
tgt_id = id_map.get(tgt_n)
284+
if src_id and tgt_id:
285+
if "compose" in rtype or "composition" in rtype:
286+
cells.append(_edge(nid(), "", S_COMPOSE, src_id, tgt_id))
287+
elif "aggregate" in rtype or "aggregation" in rtype:
288+
cells.append(_edge(nid(), "", S_AGGREGATE, src_id, tgt_id))
289+
elif "realize" in rtype or "implements" in rtype:
290+
cells.append(_edge(nid(), "", S_REALIZE, src_id, tgt_id))
291+
elif "depend" in rtype or "uses" in rtype:
292+
cells.append(_edge(nid(), "", S_DEPEND, src_id, tgt_id))
293+
elif "inherit" in rtype or "extends" in rtype:
294+
cells.append(_edge(nid(), "", S_INHERIT, src_id, tgt_id))
295+
else:
296+
cells.append(_edge(nid(), "", S_ASSOCIATE, src_id, tgt_id))
297+
254298
if not cells:
255299
cells.append(_vertex(nid(), "No classes found", S_ACT_ACTION, 100, 100, 200, 50))
256300

0 commit comments

Comments
 (0)