From 159b7b7682e3629ba4c520fc5602478c96b94378 Mon Sep 17 00:00:00 2001 From: Edward Viaene Date: Fri, 30 Oct 2026 13:29:34 -0500 Subject: [PATCH] set_wiring takes back what wiring returned: pass loop_output_* through The server keeps these keys in the profile. An agent reading the profile and saving it with one new value was refused with "unknown key", found saving a flash target through the AI HIL tab. Co-Authored-By: Claude Opus 5.5 --- packages/embeddedci-mcp/CHANGELOG.md | 2 ++ packages/embeddedci-mcp/tests/test_wiring_tools.py | 11 +++++++++++ packages/embeddedci/src/embeddedci/benchpod/wiring.py | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/embeddedci-mcp/CHANGELOG.md b/packages/embeddedci-mcp/CHANGELOG.md index beeaeb3..8ca82bb 100644 --- a/packages/embeddedci-mcp/CHANGELOG.md +++ b/packages/embeddedci-mcp/CHANGELOG.md @@ -7,6 +7,8 @@ `analog_path`, `adc_read` and `capture_adc` take `range`; `calibrate_adc_gain` takes `range=low` for the low range's gain. `adc_read` reports `range`, `fullscale` and `overrange`, `capture_adc` `range` and `clipped_samples`, `calibration` `adc_low_gain_ppm`. +- `set_wiring` takes back what `wiring` returned: the server's `loop_output_*` keys pass through + like `loop_input_*`, so reading the profile, changing a value and saving it works and keeps them. - Requires embeddedci 2.13.4. ## 2.13.3 diff --git a/packages/embeddedci-mcp/tests/test_wiring_tools.py b/packages/embeddedci-mcp/tests/test_wiring_tools.py index 61979e5..ec73891 100644 --- a/packages/embeddedci-mcp/tests/test_wiring_tools.py +++ b/packages/embeddedci-mcp/tests/test_wiring_tools.py @@ -165,3 +165,14 @@ def test_signals_reach_gpio_and_trigger_arguments(connected): assert call("gpio_mode", la=["TRIGGER"])["pins"][0]["la"] == 9 assert call("capture_la", samples=64, sample_rate_hz=1e6, trigger_la="TRIGGER")["trigger"] == "LA9 rising" + + +def test_set_wiring_takes_back_what_wiring_returned(connected): + # The server keeps loop_input_* and loop_output_* in the profile: an agent that reads the + # profile, changes one value and writes it back must not be refused, or lose them. + stored = {"swd_target": "", "loop_input_unit": "mA", "loop_output_enabled": True, "loop_output_max_v": 3.3} + SESSION.require().wiring = Wiring.from_dict(stored, strict=False) + profile = call("wiring")["profile"] + result = call("set_wiring", profile={**profile, "swd_target": "target/stm32f4x.cfg"}) + assert result["swd_target"] == "target/stm32f4x.cfg" + assert SESSION.require().wiring.extra["loop_output_max_v"] == 3.3 diff --git a/packages/embeddedci/src/embeddedci/benchpod/wiring.py b/packages/embeddedci/src/embeddedci/benchpod/wiring.py index b17aa64..863262c 100644 --- a/packages/embeddedci/src/embeddedci/benchpod/wiring.py +++ b/packages/embeddedci/src/embeddedci/benchpod/wiring.py @@ -34,7 +34,7 @@ _NAME = re.compile(r"^[A-Za-z][A-Za-z0-9_]{0,31}$") _SIGNAL_KEYS = ("name", "la", "direction", "active_low", "description") #: Keys other parts of the product keep in the profile; the SDK passes them through untouched. -_PASSTHROUGH_PREFIXES = ("loop_input_",) +_PASSTHROUGH_PREFIXES = ("loop_input_", "loop_output_") def _is_int(value: Any) -> bool: