diff --git a/signalwire/signalwire/core/function_result.py b/signalwire/signalwire/core/function_result.py index 23f3d286..60607b05 100644 --- a/signalwire/signalwire/core/function_result.py +++ b/signalwire/signalwire/core/function_result.py @@ -480,7 +480,7 @@ def execute_swml( """ # Detect input type and normalize to appropriate format if isinstance(swml_content, str): - # Raw SWML string - parse to dict so we can add transfer key if needed + # Raw SWML string - parse to dict so the action carries a document try: import json @@ -496,11 +496,15 @@ def execute_swml( else: raise TypeError("swml_content must be string, dict, or SWML object") - action = swml_data + # transfer rides BESIDE the SWML document, not inside it — the same + # shape connect() and swml_transfer() emit. Inside the document it is + # not a SWML key and the call never exits the agent. + action: dict[str, Any] = {"SWML": swml_data} if transfer: action["transfer"] = "true" - return self.add_action("SWML", action) + self.action.append(action) + return self def hangup(self) -> "FunctionResult": """ diff --git a/tests/unit/core/test_function_result.py b/tests/unit/core/test_function_result.py index 0803de39..842fd4d8 100644 --- a/tests/unit/core/test_function_result.py +++ b/tests/unit/core/test_function_result.py @@ -542,8 +542,8 @@ def test_execute_swml_dict_does_not_mutate_original(self) -> None: # The original dict should NOT have 'transfer' key added assert "transfer" not in original - # But the action's SWML should have it - assert result.action[0]["SWML"]["transfer"] == "true" + # The action carries it beside the document + assert result.action[0]["transfer"] == "true" def test_execute_swml_sdk_object_with_to_dict(self) -> None: """Test execute_swml with an SDK object that has to_dict()""" @@ -568,12 +568,18 @@ def test_execute_swml_invalid_type_list(self) -> None: FunctionResult().execute_swml([1, 2, 3]) def test_execute_swml_with_transfer_true(self) -> None: - """Test execute_swml with transfer=True adds transfer key""" + """transfer is a SIBLING of the SWML key — the platform's documented + action shape, and the one connect()/swml_transfer() emit. Inside the + document it is not a SWML key and the call never exits the agent.""" swml_dict = {"version": "1.0.0", "sections": {"main": []}} result = FunctionResult().execute_swml(swml_dict, transfer=True) action = result.action[0] - assert action["SWML"]["transfer"] == "true" + assert action["transfer"] == "true" + assert "transfer" not in action["SWML"] + # Same action shape as the live-proven connect() helper + connect_action = FunctionResult().connect("+15551234567").action[0] + assert set(action.keys()) == set(connect_action.keys()) def test_execute_swml_with_transfer_false(self) -> None: """Test execute_swml with transfer=False does not add transfer key""" @@ -581,6 +587,7 @@ def test_execute_swml_with_transfer_false(self) -> None: result = FunctionResult().execute_swml(swml_dict, transfer=False) action = result.action[0] + assert "transfer" not in action assert "transfer" not in action["SWML"] def test_execute_swml_chaining(self) -> None: