[Bug]: qwen3 + full skill set + tools causes streaming timeout on Ollama (api-format=openai)
Environment
- OpenHarness 0.1.9 (
pip install -e .from main) - Ollama on remote host (
192.168.50.240:11434), forwarded viasocat TCP-LISTEN:11434,fork,reuseaddr TCP:192.168.50.240:11434(OpenHarness's Ollama provider detection hard-codeslocalhost:11434) - Model:
qwen3:14b-64k(qwen3 family, thinking-mode enabled by default) - Python 3.12.3, Ubuntu 24.04
What happened
Running oh -p "<any prompt>" with --api-format openai --base-url http://localhost:11434/v1 --model qwen3:14b-64k against Ollama hangs ~30s and returns:
API error: Request timed out.Happens regardless of --max-turns 1 through --max-turns 8, as long as the full skill set (8 skills) and 39 built-in tools are injected.
Steps to reproduce
oh -p "Read /tmp/oh-test/main.py and use the **plan** skill. Output a 3-step refactor plan only." \
--model "qwen3:14b-64k" \
--base-url "http://localhost:11434/v1" \
--api-key "ollama" \
--api-format "openai" \
--max-turns 4Result: hangs ~30s, then API error: Request timed out.
What works
--bare(skips skills/plugins/MCP) returns in ~3s. Model itself is fine.- Direct
curlto Ollama's/v1/chat/completionswith the same prompt (no OpenHarness wrapper) returns immediately. Ollama is fine. - Switching to
qwen2.5-coder:7b(non-thinking) works end-to-end for all 8 skills. So the model family is the trigger.
Root cause hypothesis
src/openharness/api/openai_client.py:325-333 already documents that stream_options is omitted when tools are present to avoid triggering Kimi-style thinking mode:
if openai_tools:
params["tools"] = openai_tools
# Some providers (Kimi) error on empty reasoning_content in
# tool-call follow-ups. Omit the entire stream_options key if
# tools are present – avoids triggering model-side thinking mode
params.pop("stream_options", None)But qwen3's thinking mode is triggered by something other than stream_options — likely a model-specific prompt template flag or system token. When 39 tools are injected (raising total prompt size to ~8k+ tokens) the thinking trace becomes very long, and OpenHarness's streaming parser appears to hang waiting for either the final message or a reasoning-content boundary that never comes.
The same code path works for non-thinking models (qwen2.5-coder:7b) because there is no reasoning trace to wait for.
Suggested fixes (any one)
- Add a per-model reasoning hint to the request: for qwen3 models, pass
chat_template_kwargs: {"enable_thinking": false}(or equivalent for the model family) to disable thinking entirely. Ollama's/v1/chat/completionsendpoint forwards this to the model template. - Add a configurable request timeout that's more aggressive than the default, so qwen3 hangs fail fast and surface as a clear "thinking-mode-incompatible" error rather than a generic timeout.
- Add a streaming watchdog that, if no content delta arrives within N seconds, kills the connection and optionally falls back to a non-thinking model variant.
Impact
Anyone trying to use OpenHarness with a local Ollama backend running qwen3 will hit this immediately and may conclude OpenHarness is broken. This blocks the entire "local-only" workflow that OpenHarness advertises as a key differentiator from Claude Code.
Related
- #319 (Ollama provider auth, closed 2026-06-27)
- #292 (custom skills execution, still open)
Source: HKUDS/OpenHarness