1+ import datetime
12import json
3+ import os
24import time
5+ import traceback
36from typing import Optional
47from secrets import token_hex
58from lmos_openai_types import (
811 CreateChatCompletionRequest ,
912 CreateChatCompletionStreamResponse ,
1013 Function1 ,
14+ FinishReason1 ,
1115)
1216
1317from mcp_bridge .inference_engine_mappers .chat .requester import chat_completion_requester
1418from mcp_bridge .inference_engine_mappers .chat .stream_responder import (
1519 chat_completion_stream_responder ,
1620)
17- from .utils import call_tool , chat_completion_add_tools
21+ from .utils import (
22+ call_tool ,
23+ chat_completion_add_tools ,
24+ validate_if_json_object_parsable ,
25+ salvage_parsable_json_object ,
26+ )
1827from mcp_bridge .models import SSEData , upstream_error
1928from mcp_bridge .http_clients import get_client
2029from loguru import logger
@@ -68,9 +77,9 @@ async def chat_completions(request: CreateChatCompletionRequest):
6877 # exclude_defaults=True, exclude_none=True, exclude_unset=True
6978 # )
7079
71- json_data = json .dumps (chat_completion_requester (request ))
80+ json_data = json .dumps (chat_completion_requester (request ), indent = 4 , ensure_ascii = False )
7281
73- # logger.debug(json_data)
82+ logger .debug ("Request JSON: \n %s" % json_data )
7483
7584 last : Optional [CreateChatCompletionStreamResponse ] = None # last message
7685
@@ -211,6 +220,29 @@ async def chat_completions(request: CreateChatCompletionRequest):
211220 # save the last message
212221 last = parsed_data
213222
223+ # perform early stopping on parsable tool_call_json
224+ if tool_call_json :
225+ if tool_call_json .strip ().startswith ("{" ):
226+ if validate_if_json_object_parsable (tool_call_json ):
227+ logger .debug (
228+ f"tool call json '{ tool_call_json } ' is parsable now."
229+ )
230+ logger .debug ("exiting message receive loop" )
231+ last .choices [0 ].finish_reason = FinishReason1 .tool_calls
232+ break
233+ salvaged_json_object = salvage_parsable_json_object (
234+ tool_call_json
235+ )
236+ if salvaged_json_object :
237+ tool_call_json = salvaged_json_object
238+ logger .debug (
239+ f"tool call json '{ tool_call_json } ' is salvagable now."
240+ )
241+ logger .debug ("salvaged json content:" , tool_call_json )
242+ logger .debug ("exiting message receive loop" )
243+ last .choices [0 ].finish_reason = FinishReason1 .tool_calls
244+ break
245+
214246 # ideally we should check this properly
215247 assert last is not None
216248
@@ -229,6 +261,9 @@ async def chat_completions(request: CreateChatCompletionRequest):
229261 f"{ tool_call_name = } { tool_call_json = } "
230262 ) # this should not be error but its easier to debug
231263
264+ logger .debug ("clearing tool contexts to prevent tool call loops" )
265+ request .tools = None
266+
232267 # add received message to the history
233268 msg = ChatCompletionRequestMessage (
234269 role = "assistant" ,
0 commit comments