@@ -221,14 +221,7 @@ def test_tool(param1: str, param2: int) -> str:
221221
222222 # Check basic spec properties
223223 assert spec ["name" ] == "test_tool"
224- assert (
225- spec ["description" ]
226- == """Test tool function.
227-
228- Args:
229- param1: First parameter
230- param2: Second parameter"""
231- )
224+ assert spec ["description" ] == "Test tool function."
232225
233226 # Check input schema
234227 schema = spec ["inputSchema" ]["json" ]
@@ -310,6 +303,174 @@ def test_tool(required: str, optional: Optional[int] = None) -> str:
310303 exp_events = [
311304 ToolResultEvent ({"toolUseId" : "test-id" , "status" : "success" , "content" : [{"text" : "Result: hello 42" }]})
312305 ]
306+ assert tru_events == exp_events
307+
308+
309+ @pytest .mark .asyncio
310+ async def test_docstring_description_extraction ():
311+ """Test that docstring descriptions are extracted correctly, excluding Args section."""
312+
313+ @strands .tool
314+ def tool_with_full_docstring (param1 : str , param2 : int ) -> str :
315+ """This is the main description.
316+
317+ This is more description text.
318+
319+ Args:
320+ param1: First parameter
321+ param2: Second parameter
322+
323+ Returns:
324+ A string result
325+
326+ Raises:
327+ ValueError: If something goes wrong
328+ """
329+ return f"{ param1 } { param2 } "
330+
331+ spec = tool_with_full_docstring .tool_spec
332+ assert (
333+ spec ["description" ]
334+ == """This is the main description.
335+
336+ This is more description text.
337+
338+ Returns:
339+ A string result
340+
341+ Raises:
342+ ValueError: If something goes wrong"""
343+ )
344+
345+
346+ def test_docstring_args_variations ():
347+ """Test that various Args section formats are properly excluded."""
348+
349+ @strands .tool
350+ def tool_with_args (param : str ) -> str :
351+ """Main description.
352+
353+ Args:
354+ param: Parameter description
355+ """
356+ return param
357+
358+ @strands .tool
359+ def tool_with_arguments (param : str ) -> str :
360+ """Main description.
361+
362+ Arguments:
363+ param: Parameter description
364+ """
365+ return param
366+
367+ @strands .tool
368+ def tool_with_parameters (param : str ) -> str :
369+ """Main description.
370+
371+ Parameters:
372+ param: Parameter description
373+ """
374+ return param
375+
376+ @strands .tool
377+ def tool_with_params (param : str ) -> str :
378+ """Main description.
379+
380+ Params:
381+ param: Parameter description
382+ """
383+ return param
384+
385+ for tool in [tool_with_args , tool_with_arguments , tool_with_parameters , tool_with_params ]:
386+ spec = tool .tool_spec
387+ assert spec ["description" ] == "Main description."
388+
389+
390+ def test_docstring_no_args_section ():
391+ """Test docstring extraction when there's no Args section."""
392+
393+ @strands .tool
394+ def tool_no_args (param : str ) -> str :
395+ """This is the complete description.
396+
397+ Returns:
398+ A string result
399+ """
400+ return param
401+
402+ spec = tool_no_args .tool_spec
403+ expected_desc = """This is the complete description.
404+
405+ Returns:
406+ A string result"""
407+ assert spec ["description" ] == expected_desc
408+
409+
410+ def test_docstring_only_args_section ():
411+ """Test docstring extraction when there's only an Args section."""
412+
413+ @strands .tool
414+ def tool_only_args (param : str ) -> str :
415+ """Args:
416+ param: Parameter description
417+ """
418+ return param
419+
420+ spec = tool_only_args .tool_spec
421+ # Should fall back to function name when no description remains
422+ assert spec ["description" ] == "tool_only_args"
423+
424+
425+ def test_docstring_empty ():
426+ """Test docstring extraction when docstring is empty."""
427+
428+ @strands .tool
429+ def tool_empty_docstring (param : str ) -> str :
430+ return param
431+
432+ spec = tool_empty_docstring .tool_spec
433+ # Should fall back to function name
434+ assert spec ["description" ] == "tool_empty_docstring"
435+
436+
437+ def test_docstring_preserves_other_sections ():
438+ """Test that non-Args sections are preserved in the description."""
439+
440+ @strands .tool
441+ def tool_multiple_sections (param : str ) -> str :
442+ """Main description here.
443+
444+ Args:
445+ param: This should be excluded
446+
447+ Returns:
448+ This should be included
449+
450+ Raises:
451+ ValueError: This should be included
452+
453+ Examples:
454+ This should be included
455+
456+ Note:
457+ This should be included
458+ """
459+ return param
460+
461+ spec = tool_multiple_sections .tool_spec
462+ description = spec ["description" ]
463+
464+ # Should include main description and other sections
465+ assert "Main description here." in description
466+ assert "Returns:" in description
467+ assert "This should be included" in description
468+ assert "Raises:" in description
469+ assert "Examples:" in description
470+ assert "Note:" in description
471+
472+ # Should exclude Args section
473+ assert "This should be excluded" not in description
313474
314475
315476@pytest .mark .asyncio
0 commit comments