Support defer_loading field at function level for Chat Completions API (#22702)

Co-authored-by: Xinyuan Tong <115166877+JustinTong0323@users.noreply.github.com>
This commit is contained in:
Yuxuan Zhang
2026-04-22 10:09:54 -07:00
committed by GitHub
co-authored by Xinyuan Tong
parent 92f28e9ba8
commit 28cfd3d272
5 changed files with 145 additions and 28 deletions
@@ -24,8 +24,10 @@ from sglang.srt.entrypoints.openai.protocol import (
ChatCompletionResponseChoice,
ChatMessage,
CompletionRequest,
Function,
ModelCard,
ModelList,
Tool,
UsageInfo,
)
from sglang.test.ci.ci_register import register_cpu_ci
@@ -336,6 +338,72 @@ class TestModelSerialization(unittest.TestCase):
self.assertEqual(data["choices"][0]["hidden_states"], [0.1, 0.2, 0.3])
class TestFunctionDeferLoading(unittest.TestCase):
"""Test defer_loading field behavior on Function/Tool."""
def test_function_defaults_preserve_strict(self):
"""strict must default to False and be present in dumps so downstream
code (function_call_parser, chat templates) sees the expected shape."""
f = Function(name="foo")
data = f.model_dump()
self.assertEqual(data["name"], "foo")
self.assertEqual(data["strict"], False)
self.assertNotIn("defer_loading", data)
def test_function_defer_loading_true_serialized(self):
f = Function(name="foo", defer_loading=True)
data = f.model_dump()
self.assertTrue(data["defer_loading"])
self.assertEqual(data["strict"], False)
def test_function_defer_loading_false_serialized(self):
"""defer_loading=False is an explicit value and must be preserved."""
f = Function(name="foo", defer_loading=False)
data = f.model_dump()
self.assertIn("defer_loading", data)
self.assertFalse(data["defer_loading"])
def test_tool_level_defer_loading_propagates_to_function(self):
"""defer_loading at the Tool level should propagate to Function."""
tool = Tool(
type="function",
defer_loading=True,
function={"name": "search_db"},
)
self.assertTrue(tool.function.defer_loading)
data = tool.model_dump()
self.assertTrue(data["function"]["defer_loading"])
def test_function_level_defer_loading_wins_over_tool_level(self):
"""Explicit function-level value is preserved when both set."""
tool = Tool(
type="function",
defer_loading=True,
function={"name": "search_db", "defer_loading": False},
)
self.assertFalse(tool.function.defer_loading)
def test_tool_reference_content_part_accepted(self):
"""Chat completion should accept tool_reference content on tool-role
messages (GLM-specific extension consumed by the chat template)."""
messages = [
{
"role": "tool",
"tool_call_id": "call_1",
"content": [
{"type": "tool_reference", "name": "search_db"},
{"type": "text", "text": "ok"},
],
},
]
request = ChatCompletionRequest(model="test-model", messages=messages)
parts = request.messages[0].content
self.assertEqual(len(parts), 2)
self.assertEqual(parts[0].type, "tool_reference")
self.assertEqual(parts[0].name, "search_db")
self.assertEqual(parts[1].type, "text")
class TestValidationEdgeCases(unittest.TestCase):
"""Test edge cases and validation scenarios"""