22
33# Adapted from
44# https://github.com/lm-sys/FastChat/blob/168ccc29d3f7edc50823016105c024fe2282732a/fastchat/protocol/openai_api_protocol.py
5+ import json
56import re
67import time
78from argparse import Namespace
@@ -139,12 +140,30 @@ class JsonSchemaResponseFormat(OpenAIBaseModel):
139140 strict : Optional [bool ] = None
140141
141142
143+ class StructuralTag (OpenAIBaseModel ):
144+ begin : str
145+ # schema is the field, but that causes conflicts with pydantic so
146+ # instead use structural_tag_schema with an alias
147+ structural_tag_schema : Optional [dict [str , Any ]] = Field (default = None ,
148+ alias = "schema" )
149+ end : str
150+
151+
152+ class StructuralTagResponseFormat (OpenAIBaseModel ):
153+ type : Literal ["structural_tag" ]
154+ structures : list [StructuralTag ]
155+ triggers : list [str ]
156+
157+
142158class ResponseFormat (OpenAIBaseModel ):
143- # type must be "json_schema", "json_object" or "text"
159+ # type must be "json_schema", "json_object", or "text"
144160 type : Literal ["text" , "json_object" , "json_schema" ]
145161 json_schema : Optional [JsonSchemaResponseFormat ] = None
146162
147163
164+ AnyResponseFormat = Union [ResponseFormat , StructuralTagResponseFormat ]
165+
166+
148167class StreamOptions (OpenAIBaseModel ):
149168 include_usage : Optional [bool ] = True
150169 continuous_usage_stats : Optional [bool ] = False
@@ -227,7 +246,7 @@ class ChatCompletionRequest(OpenAIBaseModel):
227246 max_completion_tokens : Optional [int ] = None
228247 n : Optional [int ] = 1
229248 presence_penalty : Optional [float ] = 0.0
230- response_format : Optional [ResponseFormat ] = None
249+ response_format : Optional [AnyResponseFormat ] = None
231250 seed : Optional [int ] = Field (None , ge = _LONG_INFO .min , le = _LONG_INFO .max )
232251 stop : Optional [Union [str , list [str ]]] = Field (default_factory = list )
233252 stream : Optional [bool ] = False
@@ -340,6 +359,11 @@ class ChatCompletionRequest(OpenAIBaseModel):
340359 description = (
341360 "If specified, the output will follow the context free grammar." ),
342361 )
362+ structural_tag : Optional [str ] = Field (
363+ default = None ,
364+ description = (
365+ "If specified, the output will follow the structural tag schema." ),
366+ )
343367 guided_decoding_backend : Optional [str ] = Field (
344368 default = None ,
345369 description = (
@@ -476,6 +500,12 @@ def to_sampling_params(
476500 json_schema = self .response_format .json_schema
477501 assert json_schema is not None
478502 self .guided_json = json_schema .json_schema
503+ elif self .response_format .type == "structural_tag" :
504+ structural_tag = self .response_format
505+ assert structural_tag is not None and isinstance (
506+ structural_tag , StructuralTagResponseFormat )
507+ s_tag_obj = structural_tag .model_dump (by_alias = True )
508+ self .structural_tag = json .dumps (s_tag_obj )
479509
480510 guided_decoding = GuidedDecodingParams .from_optional (
481511 json = self ._get_guided_json_from_tool () or self .guided_json ,
@@ -485,6 +515,7 @@ def to_sampling_params(
485515 json_object = guided_json_object ,
486516 backend = self .guided_decoding_backend ,
487517 whitespace_pattern = self .guided_whitespace_pattern ,
518+ structural_tag = self .structural_tag ,
488519 )
489520
490521 return SamplingParams .from_optional (
@@ -742,12 +773,13 @@ class CompletionRequest(OpenAIBaseModel):
742773 "If true (the default), special tokens (e.g. BOS) will be added to "
743774 "the prompt." ),
744775 )
745- response_format : Optional [ResponseFormat ] = Field (
776+ response_format : Optional [AnyResponseFormat ] = Field (
746777 default = None ,
747- description =
748- ("Similar to chat completion, this parameter specifies the format of "
749- "output. Only {'type': 'json_object'}, {'type': 'json_schema'} or "
750- "{'type': 'text' } is supported." ),
778+ description = (
779+ "Similar to chat completion, this parameter specifies the format "
780+ "of output. Only {'type': 'json_object'}, {'type': 'json_schema'}"
781+ ", {'type': 'structural_tag'}, or {'type': 'text' } is supported."
782+ ),
751783 )
752784 guided_json : Optional [Union [str , dict , BaseModel ]] = Field (
753785 default = None ,
0 commit comments