Environment
- OpenHarness 0.1.9 (
pip install -e . from main)
- Ollama on remote host (
192.168.50.240:11434), forwarded via socat TCP-LISTEN:11434,fork,reuseaddr TCP:192.168.50.240:11434 (OpenHarness's Ollama provider detection hard-codes localhost: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 4
Result: hangs ~30s, then API error: Request timed out.
What works
--bare (skips skills/plugins/MCP) returns in ~3s. Model itself is fine.
- Direct
curl to Ollama's /v1/chat/completions with 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/completions endpoint 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
Environment
pip install -e .from main)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)qwen3:14b-64k(qwen3 family, thinking-mode enabled by default)What happened
Running
oh -p "<any prompt>"with--api-format openai --base-url http://localhost:11434/v1 --model qwen3:14b-64kagainst Ollama hangs ~30s and returns:Happens regardless of
--max-turns 1through--max-turns 8, as long as the full skill set (8 skills) and 39 built-in tools are injected.Steps to reproduce
Result: hangs ~30s, then
API error: Request timed out.What works
--bare(skips skills/plugins/MCP) returns in ~3s. Model itself is fine.curlto Ollama's/v1/chat/completionswith the same prompt (no OpenHarness wrapper) returns immediately. Ollama is fine.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-333already documents thatstream_optionsis omitted when tools are present to avoid triggering Kimi-style thinking mode: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)
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.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