Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions src/engine/ov_genai/qwen_tool_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def _step(self, content_out: list, fragments: list) -> bool:
self.status = StreamingStatus.TOOL_CALL_STOP
return True
self._buf = buf[len(TOOL_OPEN):]
self._start_call(fragments)
self._start_call()
self._state = IN_TOOL_CALL
return True

Expand All @@ -238,11 +238,7 @@ def _step(self, content_out: list, fragments: list) -> bool:
return False
name = buf[:gt].strip()
self._buf = buf[gt + 1:]
self._cur["function"]["name"] = name
fragments.append({
"index": len(self._calls) - 1,
"function": {"name": name},
})
self._register_call(name, fragments)
self._state = IN_FUNCTION
return True

Expand Down Expand Up @@ -332,19 +328,28 @@ def _frag(self, fragments: list, arguments: str):
})
self._cur["function"]["arguments"] += arguments

def _start_call(self, fragments: list):
def _start_call(self):
# Pending only: not registered in `_calls` (and no fragment emitted)
# until `_register_call` confirms this is really Qwen's
# <function=NAME> syntax. A <tool_call> block using a different
# format (e.g. Hermes-style raw JSON) never registers, so it can't
# surface as a bogus half-empty tool call - it's left for the
# accumulated-text Hermes fallback in openai.py to pick up instead.
self._cur = {
"id": f"call_{next(self._ids):024x}",
"type": "function",
"function": {"name": "", "arguments": ""},
}
self._calls.append(self._cur)
self._param_index = 0

def _register_call(self, name: str, fragments: list):
self._cur["function"]["name"] = name
self._calls.append(self._cur)
fragments.append({
"index": len(self._calls) - 1,
"id": self._cur["id"],
"type": "function",
"function": {"name": "", "arguments": ""},
"function": {"name": name, "arguments": ""},
})

def _close_call(self, fragments: list):
Expand Down
9 changes: 4 additions & 5 deletions src/server/routes/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,10 @@ async def openai_chat_completions(
created_ts = int(time.time())
request_id = f"ov-{uuid.uuid4().hex[:24]}"

thinking_enabled = True
if chat_template_kwargs:
thinking_enabled = chat_template_kwargs.get(
"enable_thinking", True
)
# Don't assume hybrid-thinking mode unless told to expect it (see PR
# description): models without a closing </think> tag would otherwise
# have their entire streamed answer misclassified as reasoning_content.
thinking_enabled = bool(chat_template_kwargs.get("enable_thinking", False))

if generation_config.stream:

Expand Down