@@ -88,6 +88,10 @@ class InputSchema(BaseModel):
8888 userId : str
8989 searchQuery : str
9090
91+ class ToolArgs (BaseModel ):
92+ user_id : str
93+ query : str
94+
9195 tool = _create_tool (
9296 "test_tool" ,
9397 {
@@ -98,6 +102,7 @@ class InputSchema(BaseModel):
98102 is_sensitive = False , argument_path = "searchQuery"
99103 ),
100104 },
105+ args_schema = ToolArgs ,
101106 )
102107 handler = StaticArgsHandler ()
103108 state = InputSchema (userId = "user123" , searchQuery = "test search" )
@@ -114,6 +119,10 @@ def test_initialize_with_mixed_static_and_argument_properties(self):
114119 class InputSchema (BaseModel ):
115120 userId : str
116121
122+ class ToolArgs (BaseModel ):
123+ api_key : str
124+ user_id : str
125+
117126 tool = _create_tool (
118127 "test_tool" ,
119128 {
@@ -124,6 +133,7 @@ class InputSchema(BaseModel):
124133 is_sensitive = False , argument_path = "userId"
125134 ),
126135 },
136+ args_schema = ToolArgs ,
127137 )
128138 handler = StaticArgsHandler ()
129139 handler .initialize ([tool ], InputSchema (userId = "user456" ), InputSchema )
@@ -140,6 +150,10 @@ class InputSchema(BaseModel):
140150 existingArg : str
141151 missingArg : str = ""
142152
153+ class ToolArgs (BaseModel ):
154+ existing_param : str
155+ missing_param : str = ""
156+
143157 tool = _create_tool (
144158 "test_tool" ,
145159 {
@@ -150,6 +164,7 @@ class InputSchema(BaseModel):
150164 is_sensitive = False , argument_path = "nonExistentField"
151165 ),
152166 },
167+ args_schema = ToolArgs ,
153168 )
154169 handler = StaticArgsHandler ()
155170 handler .initialize ([tool ], InputSchema (existingArg = "exists" ), InputSchema )
@@ -159,6 +174,31 @@ class InputSchema(BaseModel):
159174 assert call ["args" ]["existing_param" ] == "exists"
160175 assert "missing_param" not in call ["args" ]
161176
177+ def test_initialize_with_all_argument_properties_unresolved (self ):
178+ """A tool whose argument properties all resolve to nothing is returned
179+ unchanged and threads no static args into the call."""
180+
181+ class InputSchema (BaseModel ):
182+ present : str = ""
183+
184+ tool = _create_tool (
185+ "test_tool" ,
186+ {
187+ "$['query']" : AgentToolArgumentArgumentProperties (
188+ is_sensitive = False , argument_path = "absentField"
189+ ),
190+ },
191+ )
192+ handler = StaticArgsHandler ()
193+ processed_tools = handler .initialize ([tool ], InputSchema (), InputSchema )
194+
195+ # No static args resolved, so the original tool passes through unmodified.
196+ assert processed_tools [0 ] is tool
197+
198+ call = _make_tool_call ("test_tool" , {"host" : "h" })
199+ handler .apply_to_response ([call ])
200+ assert call ["args" ] == {"host" : "h" }
201+
162202 def test_apply_to_response_merges_with_existing_args (self ):
163203 """Test that apply_to_response merges static args with existing tool call args."""
164204 tool = _create_tool (
@@ -250,6 +290,33 @@ def test_initialize_returns_original_tool_when_no_static_args(self):
250290 assert len (processed_tools ) == 1
251291 assert processed_tools [0 ] is tool
252292
293+ def test_initialize_keeps_static_args_when_schema_is_not_a_model (self ):
294+ """A tool without a dict/BaseModel schema can't be schema-filtered, so its
295+ static args pass through unchanged and the tool is returned as-is."""
296+
297+ async def tool_fn (** kwargs : Any ) -> str :
298+ return "ok"
299+
300+ tool = StructuredToolWithArgumentProperties (
301+ name = "test_tool" ,
302+ description = "A test tool" ,
303+ args_schema = None ,
304+ coroutine = tool_fn ,
305+ output_type = None ,
306+ argument_properties = {
307+ "$['x']" : AgentToolStaticArgumentProperties (
308+ is_sensitive = False , value = "v"
309+ ),
310+ },
311+ )
312+ handler = StaticArgsHandler ()
313+ processed_tools = handler .initialize ([tool ], EmptyInput (), EmptyInput )
314+ assert processed_tools [0 ] is tool
315+
316+ call = _make_tool_call ("test_tool" )
317+ handler .apply_to_response ([call ])
318+ assert call ["args" ] == {"x" : "v" }
319+
253320 def test_initialize_skips_nonexistent_schema_fields (self ):
254321 """Test that static properties referencing nonexistent schema fields are skipped."""
255322 tool = _create_tool (
@@ -275,6 +342,53 @@ def test_initialize_skips_nonexistent_schema_fields(self):
275342 assert host_def ["enum" ] == ["api.example.com" ]
276343 assert "nonexistent_field" not in schema ["properties" ]
277344
345+ def test_static_arg_skipped_from_schema_is_not_applied_to_tool_call (self ):
346+ """
347+ A static argument whose path cannot be applied to the schema (e.g. the
348+ Integration-Service ``generateSchema`` button element, which is not a real
349+ schema property) is correctly skipped during schema modification but must
350+ also be stripped from the values threaded into the tool call. Otherwise the
351+ leaked key is rejected by the synthesized strict (``extra='forbid'``) model.
352+ """
353+ dict_schema = {
354+ "type" : "object" ,
355+ "additionalProperties" : False ,
356+ "properties" : {"query" : {"type" : "string" }},
357+ "required" : ["query" ],
358+ }
359+
360+ async def tool_fn (** kwargs : Any ) -> str :
361+ return "ok"
362+
363+ tool = StructuredToolWithArgumentProperties (
364+ name = "Search_using_String" ,
365+ description = "An Integration-Service tool" ,
366+ args_schema = dict_schema ,
367+ coroutine = tool_fn ,
368+ output_type = None ,
369+ argument_properties = {
370+ "$['generateSchema']" : AgentToolStaticArgumentProperties (
371+ is_sensitive = False , value = None
372+ ),
373+ },
374+ )
375+ handler = StaticArgsHandler ()
376+ processed_tools = handler .initialize ([tool ], EmptyInput (), EmptyInput )
377+ modified_tool = processed_tools [0 ]
378+
379+ call = _make_tool_call ("Search_using_String" , {"query" : "hello" })
380+ handler .apply_to_response ([call ])
381+
382+ # The un-inlineable path must not leak into the tool call args.
383+ assert "generateSchema" not in call ["args" ]
384+ assert call ["args" ] == {"query" : "hello" }
385+
386+ # The applied args must validate against the synthesized strict model.
387+ assert isinstance (modified_tool .args_schema , type ) and issubclass (
388+ modified_tool .args_schema , BaseModel
389+ )
390+ modified_tool .args_schema .model_validate (call ["args" ])
391+
278392
279393class TestApplyStaticArgs :
280394 """Test cases for apply_static_args function."""
0 commit comments