Selaa lähdekoodia

fix: guard bare volume numeric tokens

Problem:
- Bare volume to/at/= phrases with decimal or grouped numeric tokens bypassed the malformed-number guard and were truncated into valid integer actions.

Risk:
- The new guard must mirror only the existing bare integer syntax so valid integer forms continue to execute while malformed tokens remain non-fallback and side-effect free.
zhenyu.hu 2 viikkoa sitten
vanhempi
commit
2178563def

+ 9 - 0
src/agent_lab/application/events/builtin_plugins.py

@@ -584,6 +584,15 @@ def _unsupported_volume_numeric_arguments(
                 content,
             ),
         ),
+        (
+            "absolute",
+            "value",
+            1,
+            re.search(
+                rf"\bvolume\s*(?:to|at|=)\s*{token}",
+                content,
+            ),
+        ),
         (
             "relative",
             "delta",

+ 17 - 0
tests/test_builtin_event_plugins.py

@@ -771,6 +771,9 @@ async def test_negated_volume_requests_are_substantive_invalid_without_fallback(
         ("increase volume by 10.5", {"mode": "relative", "delta": "10.5"}),
         ("set volume to 1,000", {"mode": "absolute", "value": "1,000"}),
         ("音量增加 1,000", {"mode": "relative", "delta": "1,000"}),
+        ("volume to 40.5", {"mode": "absolute", "value": "40.5"}),
+        ("volume at 1,000", {"mode": "absolute", "value": "1,000"}),
+        ("volume=40.5", {"mode": "absolute", "value": "40.5"}),
     ],
 )
 async def test_unsupported_volume_numeric_tokens_are_not_truncated_or_fallback(
@@ -804,6 +807,20 @@ async def test_unsupported_volume_numeric_tokens_are_not_truncated_or_fallback(
     assert volume.calls == []
 
 
+@pytest.mark.parametrize("content", ["volume to 40", "volume at 40", "volume=40"])
+def test_bare_volume_integer_forms_remain_valid(content):
+    volume = RecordingVolumePort()
+    registry = build_default_tool_registry(device_volume_port=volume)
+
+    payload = registry.handle(
+        _event("bare-integer", "device.volume.adjust", {}),
+        EventExecutionContext(history=(ChatMessage(role="user", content=content),)),
+    )
+
+    assert payload["port"] == "volume"
+    assert volume.calls == [("bare-integer", "absolute", 40, None)]
+
+
 @pytest.mark.parametrize("content", ["set volume to 1000", "音量增加 1000"])
 def test_volume_resolver_captures_full_oversized_number_and_rejects_it(content):
     volume = RecordingVolumePort()