@@ -109,6 +109,90 @@ async def test_render_control_template_calls_preview_endpoint() -> None:
109109 )
110110
111111
112+ @pytest .mark .asyncio
113+ async def test_validate_control_data_accepts_template_control_input () -> None :
114+ response = Mock ()
115+ response .raise_for_status = Mock ()
116+ response .json = Mock (return_value = {"success" : True })
117+ client = SimpleNamespace (http_client = SimpleNamespace (post = AsyncMock (return_value = response )))
118+ template_input = TemplateControlInput .model_validate (
119+ {
120+ "template" : {
121+ "parameters" : {
122+ "pattern" : {
123+ "type" : "regex_re2" ,
124+ "label" : "Pattern" ,
125+ }
126+ },
127+ "definition_template" : {
128+ "execution" : "server" ,
129+ "scope" : {"step_types" : ["llm" ], "stages" : ["pre" ]},
130+ "condition" : {
131+ "selector" : {"path" : "input" },
132+ "evaluator" : {
133+ "name" : "regex" ,
134+ "config" : {"pattern" : {"$param" : "pattern" }},
135+ },
136+ },
137+ "action" : {"decision" : "deny" },
138+ },
139+ },
140+ "template_values" : {"pattern" : "hello" },
141+ }
142+ )
143+
144+ await agent_control .controls .validate_control_data (client , template_input )
145+
146+ client .http_client .post .assert_awaited_once ()
147+ _ , kwargs = client .http_client .post .await_args
148+ assert kwargs ["json" ]["data" ]["template_values" ]["pattern" ] == "hello"
149+ assert kwargs ["json" ] == {
150+ "data" : {
151+ "template" : kwargs ["json" ]["data" ]["template" ],
152+ "template_values" : {"pattern" : "hello" },
153+ }
154+ }
155+
156+
157+ @pytest .mark .asyncio
158+ async def test_set_control_data_accepts_template_control_input () -> None :
159+ response = Mock ()
160+ response .raise_for_status = Mock ()
161+ response .json = Mock (return_value = {"success" : True })
162+ client = SimpleNamespace (http_client = SimpleNamespace (put = AsyncMock (return_value = response )))
163+ template_input = TemplateControlInput .model_validate (
164+ {
165+ "template" : {
166+ "parameters" : {
167+ "pattern" : {
168+ "type" : "regex_re2" ,
169+ "label" : "Pattern" ,
170+ }
171+ },
172+ "definition_template" : {
173+ "execution" : "server" ,
174+ "scope" : {"step_types" : ["llm" ], "stages" : ["pre" ]},
175+ "condition" : {
176+ "selector" : {"path" : "input" },
177+ "evaluator" : {
178+ "name" : "regex" ,
179+ "config" : {"pattern" : {"$param" : "pattern" }},
180+ },
181+ },
182+ "action" : {"decision" : "deny" },
183+ },
184+ },
185+ "template_values" : {"pattern" : "hello" },
186+ }
187+ )
188+
189+ await agent_control .controls .set_control_data (client , 123 , template_input )
190+
191+ client .http_client .put .assert_awaited_once ()
192+ _ , kwargs = client .http_client .put .await_args
193+ assert kwargs ["json" ]["data" ]["template_values" ]["pattern" ] == "hello"
194+
195+
112196def test_to_template_control_input_reshapes_stored_control_data () -> None :
113197 template_input = agent_control .controls .to_template_control_input (
114198 {
@@ -148,3 +232,21 @@ def test_to_template_control_input_reshapes_stored_control_data() -> None:
148232
149233 assert isinstance (template_input , TemplateControlInput )
150234 assert template_input .template_values == {"pattern" : "hello" }
235+
236+
237+ def test_to_template_control_input_rejects_raw_control_data () -> None :
238+ with pytest .raises (ValueError , match = "not template-backed" ):
239+ agent_control .controls .to_template_control_input (
240+ {
241+ "execution" : "server" ,
242+ "scope" : {"step_types" : ["llm" ], "stages" : ["pre" ]},
243+ "condition" : {
244+ "selector" : {"path" : "input" },
245+ "evaluator" : {
246+ "name" : "regex" ,
247+ "config" : {"pattern" : "hello" },
248+ },
249+ },
250+ "action" : {"decision" : "deny" },
251+ }
252+ )
0 commit comments