diff --git a/CHANGELOG.md b/CHANGELOG.md index ac90d67f..86cbc2e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu ## 0.9.47 (unreleased) +- Fix: the `claude` backend no longer crashes with `AttributeError: 'ThinkingBlock'` when an extended-thinking response leads with a thinking block; the first text block is read instead (#2697, thanks @mdshzb04). - Fix: `graphify update` / `save_manifest` no longer rewrites `manifest.json` timestamps on a no-op run, so `graphify-out/` stops showing as dirty (and stops producing a trailing graph commit) when nothing changed; a genuine change still updates and persists (#2838, thanks @hopstreax). - Fix: a C# 12 primary constructor's parameters are now walked, so `class Svc(IRepo repo)` emits the `references` edge to `IRepo` and calls through `repo` resolve — previously the class silently dropped its dependency; built-in and type-parameter types are not fabricated (#2829, thanks @brobl2008). - Fix: AST-derived INFERRED edges now carry a rubric `confidence_score` keyed to the relation (`uses` 0.95, `indirect_call`/unresolved cross-file `calls` 0.85) instead of landing at the rubric-forbidden 0.5 or a flat 0.8; the INFERRED default moves 0.5→0.55 so every score-less INFERRED edge is on the discrete rubric set (#2813, thanks @abhay-codes07). diff --git a/tests/test_image_vision.py b/tests/test_image_vision.py index fa9b6398..225729c0 100644 --- a/tests/test_image_vision.py +++ b/tests/test_image_vision.py @@ -424,6 +424,18 @@ def test_anthropic_response_text_falls_back_without_text(): assert llm._anthropic_response_text(content, default="SENTINEL") == "SENTINEL" +def test_anthropic_response_text_returns_first_text_block_not_concatenation(): + """Locks the first-wins semantics: graphify's claude calls return a single + JSON payload, so the helper must return the FIRST text block, never + concatenate multiple (which would corrupt the JSON).""" + content = [ + SimpleNamespace(type="thinking", thinking="planning"), + SimpleNamespace(type="text", text=_NODE_JSON), + SimpleNamespace(type="text", text='{"nodes": [], "edges": []}'), + ] + assert llm._anthropic_response_text(content) == _NODE_JSON + + def test_call_claude_parses_thinking_model_response(tmp_path, monkeypatch): """Extended-thinking models must not crash on content[0] being ThinkingBlock.""" img, _, _ = _make_corpus(tmp_path)