From 1c5c6f5748ec263d8d4ddffe5040b40658ed7547 Mon Sep 17 00:00:00 2001 From: Mihir-Mavalankar Date: Tue, 7 Apr 2026 12:36:29 -0700 Subject: [PATCH 1/2] ref(seer): Capitalize node type headings in markdown renderer Apply .capitalize() to nodeType in _render_node so markdown headings render as "# Dashboard", "## Widget" instead of lowercase. Co-Authored-By: Claude Opus 4.6 --- src/sentry/seer/explorer/client_utils.py | 2 +- .../test_organization_seer_explorer_chat.py | 2 +- tests/sentry/seer/explorer/test_client_utils.py | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sentry/seer/explorer/client_utils.py b/src/sentry/seer/explorer/client_utils.py index c05971dab8bcad..aa8a93de729f09 100644 --- a/src/sentry/seer/explorer/client_utils.py +++ b/src/sentry/seer/explorer/client_utils.py @@ -345,7 +345,7 @@ def poll_until_done( def _render_node(node: dict[str, Any], depth: int) -> str: """Recursively render an LLMContextSnapshot node and its children as markdown.""" heading = "#" * min(depth + 1, 6) - lines = [f"{heading} {node.get('nodeType', 'unknown')}"] + lines = [f"{heading} {node.get('nodeType', 'unknown').capitalize()}"] data = node.get("data") if isinstance(data, dict): diff --git a/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py b/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py index 0cffcbd03e37a0..a72dc1bfddde8c 100644 --- a/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py +++ b/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py @@ -252,7 +252,7 @@ def test_post_json_on_page_context_converted_to_markdown( assert response.status_code == 200 call_kwargs = mock_client.start_run.call_args[1] context = call_kwargs["on_page_context"] - assert "# dashboard" in context + assert "# Dashboard" in context assert '- **title**: "My Dashboard"' in context @patch("sentry.seer.endpoints.organization_seer_explorer_chat.SeerExplorerClient") diff --git a/tests/sentry/seer/explorer/test_client_utils.py b/tests/sentry/seer/explorer/test_client_utils.py index 2bb873038e3697..83d107f92da48f 100644 --- a/tests/sentry/seer/explorer/test_client_utils.py +++ b/tests/sentry/seer/explorer/test_client_utils.py @@ -200,7 +200,7 @@ def test_single_node(self) -> None: ], } result = snapshot_to_markdown(snapshot) - assert "# dashboard" in result + assert "# Dashboard" in result assert '- **title**: "Backend Health"' in result assert "- **widgetCount**: 3" in result @@ -228,9 +228,9 @@ def test_nested_nodes(self) -> None: ], } result = snapshot_to_markdown(snapshot) - assert "# dashboard" in result - assert "## widget" in result - assert "### chart" in result + assert "# Dashboard" in result + assert "## Widget" in result + assert "### Chart" in result assert '- **query**: "count()"' in result def test_empty_nodes(self) -> None: @@ -242,7 +242,7 @@ def test_node_with_no_data(self) -> None: "nodes": [{"nodeType": "dashboard", "data": None, "children": []}], } result = snapshot_to_markdown(snapshot) - assert "# dashboard" in result + assert "# Dashboard" in result assert "not an exact screenshot" in result def test_node_with_non_dict_data(self) -> None: @@ -251,5 +251,5 @@ def test_node_with_non_dict_data(self) -> None: "nodes": [{"nodeType": "widget", "data": "some string", "children": []}], } result = snapshot_to_markdown(snapshot) - assert "# widget" in result + assert "# Widget" in result assert '- "some string"' in result From ab3705f2bdac164c6466eace20ca984f20a236eb Mon Sep 17 00:00:00 2001 From: Mihir-Mavalankar Date: Tue, 7 Apr 2026 12:40:26 -0700 Subject: [PATCH 2/2] fix(seer): Handle None nodeType in markdown renderer Use `or 'unknown'` instead of dict.get default to handle explicit None values, not just missing keys. Co-Authored-By: Claude Opus 4.6 --- src/sentry/seer/explorer/client_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/seer/explorer/client_utils.py b/src/sentry/seer/explorer/client_utils.py index aa8a93de729f09..fa0be21574d64c 100644 --- a/src/sentry/seer/explorer/client_utils.py +++ b/src/sentry/seer/explorer/client_utils.py @@ -345,7 +345,7 @@ def poll_until_done( def _render_node(node: dict[str, Any], depth: int) -> str: """Recursively render an LLMContextSnapshot node and its children as markdown.""" heading = "#" * min(depth + 1, 6) - lines = [f"{heading} {node.get('nodeType', 'unknown').capitalize()}"] + lines = [f"{heading} {(node.get('nodeType') or 'unknown').capitalize()}"] data = node.get("data") if isinstance(data, dict):