fix(agent): coerce None Switch inputs before string operators (#16320)

## Summary
- Coerce `None` canvas values to `""` before string comparison operators
in `Switch.process_operator`.
- Prevents `AttributeError` when upstream components yield `None` and
the Switch uses contains/start with/end with.

## Test plan
- [x] `.v/bin/python -m ruff check agent/component/switch.py
test/unit_test/agent/component/test_switch.py`
- [x] `.v/bin/python -m pytest
test/unit_test/agent/component/test_switch.py -q` (3 passed)

Fixes #16315

---------

Co-authored-by: Harsh Kashyap <harshkashyap@Harshs-MacBook-Pro.local>
This commit is contained in:
Harsh Kashyap
2026-06-25 11:48:24 +05:30
committed by GitHub
parent 54fb5b0fa7
commit b9445c67e2
2 changed files with 43 additions and 0 deletions

View File

@@ -1,3 +1,5 @@
import pytest
from agent.component.switch import Switch, SwitchParam
@@ -57,3 +59,41 @@ def test_switch_non_empty_and_condition_still_matches():
assert cpn.output("_next") == ["case_target"]
assert cpn.output("next") == ["case_target"]
@pytest.mark.p1
def test_switch_none_input_contains_falls_through_to_else():
param = SwitchParam()
param.conditions = [
{
"logical_operator": "and",
"items": [{"cpn_id": "answer", "operator": "contains", "value": "foo"}],
"to": ["case_target"],
}
]
param.end_cpn_ids = ["else_target"]
cpn = _switch(param, {"answer": None})
cpn._invoke()
assert cpn.output("_next") == ["else_target"]
assert cpn.output("next") == ["else_target"]
@pytest.mark.p1
def test_switch_none_value_contains_does_not_raise():
param = SwitchParam()
param.conditions = [
{
"logical_operator": "and",
"items": [{"cpn_id": "answer", "operator": "contains", "value": None}],
"to": ["case_target"],
}
]
param.end_cpn_ids = ["else_target"]
cpn = _switch(param, {"answer": "foobar"})
cpn._invoke()
assert cpn.output("_next") == ["case_target"]
assert cpn.output("next") == ["case_target"]