fix(semantic-scene): preserve page/intents when all widgets are dangling, drop dead exception-name set

- _with_known_widgets_only used to discard the entire SemanticScene
  (returning None) when filtering dangling-element-id widgets left an
  empty list, losing valid page/intents. Now returns a SemanticScene
  with widgets=[] instead, matching design.md's 'dropped, not a hard
  failure' intent.
- Removed _SDK_UNAVAILABLE_EXCEPTION_NAMES, dead code left over from an
  abandoned name-based exception-matching approach; the blanket except
  Exception already maps every SDK failure correctly.

openspec: semantic-scene capability, archived change semantic-scene-runtime
This commit is contained in:
2026-07-07 08:31:03 +08:00
parent 725bf4cd9c
commit ca5e300289
3 changed files with 6 additions and 13 deletions
+1 -3
View File
@@ -42,7 +42,7 @@ def enrich_scene(
def _with_known_widgets_only( def _with_known_widgets_only(
scene: Scene, scene: Scene,
semantic_scene: SemanticScene, semantic_scene: SemanticScene,
) -> SemanticScene | None: ) -> SemanticScene:
known_element_ids = {element.id for element in scene.elements} known_element_ids = {element.id for element in scene.elements}
if not known_element_ids: if not known_element_ids:
return semantic_scene return semantic_scene
@@ -52,8 +52,6 @@ def _with_known_widgets_only(
for widget in semantic_scene.widgets for widget in semantic_scene.widgets
if widget.element_id in known_element_ids if widget.element_id in known_element_ids
] ]
if not widgets:
return None
return SemanticScene( return SemanticScene(
page=semantic_scene.page, page=semantic_scene.page,
-8
View File
@@ -7,14 +7,6 @@ from semantic.config import DEFAULT_MODEL
from semantic.models import SEMANTIC_SCENE_SCHEMA, SemanticScene from semantic.models import SEMANTIC_SCENE_SCHEMA, SemanticScene
from semantic.prompts import ENRICHMENT_SYSTEM_PROMPT, scene_user_prompt from semantic.prompts import ENRICHMENT_SYSTEM_PROMPT, scene_user_prompt
_SDK_UNAVAILABLE_EXCEPTION_NAMES = {
"APITimeoutError",
"APIConnectionError",
"RateLimitError",
"AuthenticationError",
"APIStatusError",
}
class EnrichmentUnavailable(Exception): class EnrichmentUnavailable(Exception):
"""Internal signal for expected enrichment transport/response failures.""" """Internal signal for expected enrichment transport/response failures."""
+5 -2
View File
@@ -123,7 +123,7 @@ def test_enrich_scene_filters_dangling_element_ids() -> None:
] ]
def test_enrich_scene_returns_none_when_all_widgets_are_dangling() -> None: def test_enrich_scene_returns_empty_widgets_when_all_widgets_are_dangling() -> None:
client = FakeClient( client = FakeClient(
response={ response={
"page": "Chat", "page": "Chat",
@@ -138,4 +138,7 @@ def test_enrich_scene_returns_none_when_all_widgets_are_dangling() -> None:
config=SemanticConfig(enabled=True), config=SemanticConfig(enabled=True),
) )
assert result is None assert result is not None
assert result.page == "Chat"
assert result.intents == ["send a message"]
assert result.widgets == []