Skip to content

[Bug]: qwen3 + full skill set + tools causes streaming timeout on Ollama (api-format=openai) #320

Description

@Marvis81

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

  1. --bare (skips skills/plugins/MCP) returns in ~3s. Model itself is fine.
  2. Direct curl to Ollama's /v1/chat/completions with the same prompt (no OpenHarness wrapper) returns immediately. Ollama is fine.
  3. 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)

  1. 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.
  2. 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.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions