From 6a311c865150b79f762945eca6c4559ae198eeda Mon Sep 17 00:00:00 2001 From: Bartok9 Date: Wed, 22 Jul 2026 02:10:43 -0400 Subject: [PATCH 1/2] fix(langchain): skip non-dict models in format_list_models_content Malformed MDL rows (None/str/non-list columns) crashed the markdown table builder. Skip bad rows and coerce nested properties/columns. --- .../src/wren_langchain/_format.py | 20 +++++++++++---- .../unit/test_format_list_models_guard.py | 25 +++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 sdk/wren-langchain/tests/unit/test_format_list_models_guard.py diff --git a/sdk/wren-langchain/src/wren_langchain/_format.py b/sdk/wren-langchain/src/wren_langchain/_format.py index 82d3085197..089a53964d 100644 --- a/sdk/wren-langchain/src/wren_langchain/_format.py +++ b/sdk/wren-langchain/src/wren_langchain/_format.py @@ -137,11 +137,21 @@ def format_list_models_content(manifest: dict[str, Any]) -> str: lines = ["| model | cols | description |", "|---|---|---|"] for m in models: - name = m.get("name", "") - col_count = len(m.get("columns", []) or []) - desc = ( - (m.get("properties") or {}).get("description") or m.get("description") or "" - ) + # MDL loaders / LLM-shaped manifests may include None rows, bare + # strings, or mixed types. Non-dicts previously AttributeError'd + # on ``.get`` and aborted the whole list_models content path. + if not isinstance(m, dict): + continue + name = m.get("name", "") or "" + columns = m.get("columns", []) or [] + if not isinstance(columns, list): + columns = [] + col_count = len(columns) + props = m.get("properties") or {} + if not isinstance(props, dict): + props = {} + desc = props.get("description") or m.get("description") or "" + desc = str(desc) # Trim long descriptions to keep table compact. if len(desc) > 80: desc = desc[:77] + "..." diff --git a/sdk/wren-langchain/tests/unit/test_format_list_models_guard.py b/sdk/wren-langchain/tests/unit/test_format_list_models_guard.py new file mode 100644 index 0000000000..1f46bb1c80 --- /dev/null +++ b/sdk/wren-langchain/tests/unit/test_format_list_models_guard.py @@ -0,0 +1,25 @@ +import importlib.util +from pathlib import Path + +_ROOT = Path(__file__).resolve().parents[2] +_PATH = _ROOT / "src" / "wren_langchain" / "_format.py" +_spec = importlib.util.spec_from_file_location("_fmt", _PATH) +_mod = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(_mod) + + +def test_skips_non_dict_and_bad_nested(): + out = _mod.format_list_models_content( + { + "models": [ + None, + "x", + {"name": "ok", "columns": None, "properties": "bad", "description": "d"}, + {"name": "wide", "columns": [1, 2], "properties": {"description": "y" * 100}}, + ] + } + ) + assert "| ok |" in out + assert "| wide |" in out + assert "None" not in out.split("\n")[2] + assert "..." in out From 59d358d98474d8fea2a882fac624aedbdfbe4888 Mon Sep 17 00:00:00 2001 From: Bartok9 Date: Wed, 22 Jul 2026 04:08:40 -0400 Subject: [PATCH 2/2] style(langchain): ruff format list_models non-dict guard test CI lint fails on ruff format --check for the new unit test. --- .../tests/unit/test_format_list_models_guard.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sdk/wren-langchain/tests/unit/test_format_list_models_guard.py b/sdk/wren-langchain/tests/unit/test_format_list_models_guard.py index 1f46bb1c80..4e8e2cda6e 100644 --- a/sdk/wren-langchain/tests/unit/test_format_list_models_guard.py +++ b/sdk/wren-langchain/tests/unit/test_format_list_models_guard.py @@ -14,8 +14,17 @@ def test_skips_non_dict_and_bad_nested(): "models": [ None, "x", - {"name": "ok", "columns": None, "properties": "bad", "description": "d"}, - {"name": "wide", "columns": [1, 2], "properties": {"description": "y" * 100}}, + { + "name": "ok", + "columns": None, + "properties": "bad", + "description": "d", + }, + { + "name": "wide", + "columns": [1, 2], + "properties": {"description": "y" * 100}, + }, ] } )