Skip to content
Open
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
18 changes: 18 additions & 0 deletions src/openharness/api/openai_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@
BASE_DELAY = 1.0
MAX_DELAY = 30.0
_MAX_COMPLETION_TOKEN_MODEL_PREFIXES = ("gpt-5", "o1", "o3", "o4")
_QWEN3_MODEL_PREFIXES = ("qwen3",)


def _is_qwen3_model(model: str) -> bool:
"""Return True for qwen3-family models (Ollama or HuggingFace naming)."""
normalized = model.strip().lower()
if "/" in normalized:
normalized = normalized.rsplit("/", 1)[-1]
# Strip quantisation tag (e.g. "qwen3:14b-64k" → "qwen3")
normalized = normalized.split(":")[0]
return normalized.startswith(_QWEN3_MODEL_PREFIXES)


def _token_limit_param_for_model(model: str, max_tokens: int) -> dict[str, int]:
Expand Down Expand Up @@ -331,6 +342,13 @@ async def _stream_once(self, request: ApiMessageRequest) -> AsyncIterator[ApiStr
# tools are present – avoids triggering model-side thinking mode
# that requires reasoning_content on every assistant message.
params.pop("stream_options", None)
# qwen3 enables thinking mode via its chat template, not via
# stream_options. With 30+ tools injected the reasoning trace
# grows very large and the streaming connection times out before
# the final token arrives. Disable thinking mode explicitly when
# tools are in use so the model answers directly.
if _is_qwen3_model(request.model):
params["chat_template_kwargs"] = {"enable_thinking": False}

# Collect full response while streaming text deltas
collected_content = ""
Expand Down