openclaw - ✅(Solved) Fix [Bug]: incomplete turn detected: runId=xxx sessionId=xxx stopReason=stop payloads=0 — surfacing error to user [3 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#68076Fetched 2026-04-18 05:54:03
View on GitHub
Comments
2
Participants
3
Timeline
14
Reactions
1
Timeline (top)
cross-referenced ×5commented ×2labeled ×2referenced ×2

openclaw infer model run --model openrouter/z-ai/glm-5.1 --prompt "Reply with exactly: hello" --json 11:56:46 [agent/embedded] incomplete turn detected: runId=65e9308a-895d-4d68-b11f-07a042d2912f sessionId=65e9308a-895d-4d68-b11f-07a042d2912f stopReason=stop payloads=0 — surfacing error to user { "ok": true, "capability": "model.run", "transport": "local", "provider": "openrouter", "model": "z-ai/glm-5.1", "attempts": [], "outputs": [ { "text": "⚠️ Agent couldn't generate a response. Please try again.", "mediaUrl": null } ] }

Error Message

11:56:46 [agent/embedded] incomplete turn detected: runId=65e9308a-895d-4d68-b11f-07a042d2912f sessionId=65e9308a-895d-4d68-b11f-07a042d2912f stopReason=stop payloads=0 — surfacing error to user

Root Cause

openclaw infer model run --model openrouter/z-ai/glm-5.1 --prompt "Reply with exactly: hello" --json 11:56:46 [agent/embedded] incomplete turn detected: runId=65e9308a-895d-4d68-b11f-07a042d2912f sessionId=65e9308a-895d-4d68-b11f-07a042d2912f stopReason=stop payloads=0 — surfacing error to user { "ok": true, "capability": "model.run", "transport": "local", "provider": "openrouter", "model": "z-ai/glm-5.1", "attempts": [], "outputs": [ { "text": "⚠️ Agent couldn't generate a response. Please try again.", "mediaUrl": null } ] }

Fix Action

Fixed

PR fix notes

PR #68086: fix(agents): treat stopReason=stop as normal completion in incomplete turn detection

Description (problem / solution / changelog)

Summary

Models like glm-5.1 can return stopReason='stop' with payloads=0, which is a valid normal completion — not an incomplete turn. Previously only stopReason='error' was excluded, causing the "incomplete turn" error to surface to users erroneously.

Fix

In incomplete-turn.ts, resolveIncompleteTurnPayloadText(), add stopReason !== "stop" to the guard:

// Before:
stopReason !== "error"

// After:
stopReason !== "error" &&
stopReason !== "stop"

Behavior Change

stopReasonpayloadsBeforeAfter
"stop"0⚠️ Agent couldn't generate...null (normal)
"error"0nullnull
"stop"≥1nullnull

Closes

Closes #68076


Author: WadeY [email protected]

Changed files

  • extensions/memory-core/src/dreaming-narrative.ts (modified, +8/-3)
  • src/agents/pi-embedded-runner/run/incomplete-turn.ts (modified, +5/-1)
  • src/agents/run-wait.ts (modified, +44/-0)
  • src/agents/tools/sessions-send-tool.ts (modified, +29/-0)
  • src/logging/subsystem.ts (modified, +2/-2)

PR #68310: fix(pi-embedded-runner): retry silent stopReason=error turns (non-frontier models)

Description (problem / solution / changelog)

Summary

  • Adds a narrow, model-agnostic resubmission in the embedded runner attempt loop for turns that end with stopReason="error" + usage.output=0 + empty content[]. Bounded at 3 retries. Placed before the incompleteTurnText surface-to-user return so it actually gets a chance to fire.
  • Primary symptom: ollama/glm-5.1:cloud occasionally ends a turn this way after a successful tool-call sequence. The existing empty-response retry path (resolveEmptyResponseRetryInstruction in src/agents/pi-embedded-runner/run/incomplete-turn.ts) is gated on the strict-agentic contract (gpt-5 family only), so non-frontier models fall through to "incomplete turn detected" with payloads=0 and no recovery — the user sees no reply and has to nudge.
  • Also observed rarely on claude-opus-4-7. The guard conditions (error + zero output + empty content) are themselves vendor-neutral, so no model gating.

Closes #68281.

Why the content-empty guard is load-bearing

A reasoning-only error — where the assistant produced thinking blocks before the turn errored — also has output=0 against the typed usage shape. Without the content.length === 0 check the retry fires for those too and breaks the existing planning-only retry when the assistant ended in error coverage. Empty content distinguishes a silent crash from "the model produced hidden tokens before erroring."

Evidence

Corpus scan across ~412 session files in a long-running agent showed 23 user-nudge events ("boop" / "ahem" / "." / "continue"). 19/23 immediately follow a turn matching exactly this signature (stopReason=error, output=0, empty content, ollama/glm-5.1:cloud). See linked issue for more detail.

Test plan

  • New src/agents/pi-embedded-runner/run.empty-error-retry.test.ts:
    • Retries for ollama/glm-5.1:cloud → succeeds on 2nd attempt
    • Caps at MAX_EMPTY_ERROR_RETRIES = 3 → 4 total attempts → surfaces incomplete-turn error
    • Does NOT retry when output > 0 (preserve produced text)
    • Does NOT retry when stopReason=stop + output=0 (NO_REPLY path)
    • Retries for anthropic/claude-opus-4-7 too (model-agnostic)
  • pnpm test src/agents/pi-embedded-runner → 629/629 pass locally on this branch
  • pnpm test src/agents/pi-embedded-runner/run.empty-error-retry.test.ts → 5/5 pass
  • oxfmt / oxlint clean
  • CI (will populate after push)

Notes

  • Related but distinct from #68076: that bug is stopReason=stop payloads=0 caused by an OpenRouter baseUrl misconfiguration (a config fix). This PR addresses the stopReason=error variant (a transient model/transport crash with no existing retry path for non-frontier models). Test case 4 explicitly leaves the stop + output=0 scenario alone.
  • No changelog entry added per the repo guideline that pure bug fixes without user-visible wording changes can land without one; happy to add ### Fixes: GLM 5.1 / non-frontier models auto-retry silent error turns. to the active version block if preferred.

🤖 Generated with Claude Code

Changed files

  • src/agents/pi-embedded-runner/run.empty-error-retry.test.ts (added, +156/-0)
  • src/agents/pi-embedded-runner/run.ts (modified, +44/-1)

PR #68351: fix(openrouter): surface reasoning_details visible-text as user output (#68261)

Description (problem / solution / changelog)

Summary

  • Problem: OpenRouter model runs (e.g. openrouter/google/gemini-2.5-flash, Grok 4.x, minimax-m2.7) return blank responses with stopReason=stop payloads=0 and surface ⚠️ Agent couldn't generate a response.
  • Why it matters: Entire classes of OpenRouter-proxied models have been unusable since 2026.4.14/15 despite healthy gateway and successful upstream responses.
  • What changed: getCompletionsReasoningDelta in src/agents/openai-transport-stream.ts now discriminates the OpenRouter reasoning_details stream between hidden reasoning (reasoning.text) and OpenAI Responses–style visible output (response.output_text, response.text, text). Visible-output items are routed through the same text-block path as choice.delta.content instead of being buried in a thinking block.
  • What did NOT change (scope boundary): no changes to prompts, auth, sandbox, tool policy, secret handling, provider routing, request assembly, transcript bytes, or prompt-cache order. Previous reasoning.text behavior is preserved byte-for-byte.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #68261
  • Related #67410, #67575, #67698, #67907, #67425, #68030, #68076, #68185
  • This PR fixes a bug or regression

Root Cause

e0bf756b50 ("fix: handle OpenRouter Qwen3 reasoning_details streams") taught getCompletionsReasoningDelta to parse reasoning_details items, but it unconditionally classified every matching item as hidden thinking. Some OpenRouter upstreams (Gemini 2.5 Flash via the Responses-style reasoning proxy, xAI Grok 4.x, and related models) deliver the assistant's final answer inside reasoning_details using OpenAI Responses content types such as response.output_text, response.text, and plain text, with an empty choice.delta.content. Because the parser treated those as thinking, the stream closed with stopReason=stop, zero text blocks, and the incomplete-turn detector in src/agents/pi-embedded-runner/run/incomplete-turn.ts surfaced the generic error.

  • Root cause: reasoning_details visible-output types were misclassified as internal reasoning and never emitted as user-visible text.
  • Missing detection / guardrail: no regression covered reasoning_details streams where the final answer arrives without a separate content field.
  • Contributing context: OpenRouter's proxy layer for several reasoning models started folding visible output into reasoning_details alongside reasoning bytes.

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
  • Target test or file: src/agents/openai-transport-stream.test.ts
  • Scenario the test should lock in: a mixed reasoning_details stream where reasoning.text items stay as thinking while response.output_text, response.text, and text items surface as a user-visible text block with stopReason=stop.
  • Why this is the smallest reliable guardrail: it exercises the exact parser path that decides whether bytes become visible text or hidden thinking.
  • Existing test that already covers this: handles reasoning_details from OpenRouter/Qwen3 in completions stream only covered content + reasoning.text mixes, not the visible-text-in-reasoning_details case.

User-visible / Behavior Changes

  • OpenRouter models that deliver the final answer inside reasoning_details (e.g. Gemini 2.5 Flash, Grok 4.x) now produce visible replies instead of the generic ⚠️ Agent couldn't generate a response error. No configuration, defaults, or docs change.

Diagram

Before:
OpenRouter -> reasoning_details[{type:"response.output_text", text:"hello"}]
           -> classified as thinking
           -> stopReason=stop, payloads=0
           -> "⚠️ Agent couldn't generate a response."

After:
OpenRouter -> reasoning_details[{type:"response.output_text", text:"hello"}]
           -> classified as visible text
           -> text block "hello", stopReason=stop, payloads>=1
           -> user sees "hello"

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Runtime-enforced controls that are explicitly unchanged by this PR: tool policy/allowlist, sandbox, exec approval, subagent policy, secrets plan, owner-only gating, OpenRouter routing, auth profiles, and prompt-cache request assembly. The fix is confined to classification of bytes the upstream already returned over an authenticated, already-policy-gated channel; it does not rely on or modify any prompt text or runtime policy. A malicious upstream that labels reasoning as type: "text" cannot leak more than it could by setting choice.delta.content directly, which is already the default visible path.

Repro + Verification

Environment

  • OS: macOS (Darwin 25.3.0)
  • Runtime/container: local OpenClaw gateway (loopback)
  • Model/provider: openrouter/google/gemini-2.5-flash, openrouter/x-ai/grok-4.1-fast, openrouter/minimax/minimax-m2.7
  • Integration/channel: none (direct openclaw infer model run) and dashboard
  • Relevant config: agents.defaults.models = { "openrouter/google/gemini-2.5-flash": {} } (redacted)

Steps

  1. openclaw infer model run --model openrouter/google/gemini-2.5-flash --prompt "Reply with exactly: hello" --json
  2. Observe response contents and gateway log for incomplete turn detected ... payloads=0.
  3. Repeat for Grok 4.x / minimax-m2.7.

Expected

  • outputs[0].text contains the assistant reply.
  • No payloads=0 / incomplete turn detected warning.

Actual (before fix)

  • outputs[0].text = ⚠️ Agent couldn't generate a response. Please try again.
  • Gateway log: incomplete turn detected: ... stopReason=stop payloads=0 — surfacing error to user.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets

Before: reasoning_details visible-text items classified as thinking, zero text blocks, stopReason=stop payloads=0. After: new test surfaces reasoning_details visible-text as text while keeping reasoning.text as thinking asserts text block emission alongside the preserved thinking block; existing reasoning_details/Qwen3 and tool-call regression tests remain green.

Human Verification (required)

  • Verified scenarios:
    • pnpm test src/agents/openai-transport-stream.test.ts — 56/56 pass including the new case.
    • pnpm test src/agents/openai-transport-stream.test.ts -t reasoning_details — 4/4 reasoning_details cases pass.
    • Re-ran pnpm check (host-env-policy, tool-display, no-conflict-markers green); remaining pnpm tsgo/pnpm lint failures are pre-existing in extensions/qa-lab/src/providers/aimock/server.ts on upstream/main and unrelated to this change (verified by running pnpm tsgo on clean upstream/main).
  • Edge cases checked:
    • reasoning.text-only stream still becomes a thinking block (existing Qwen3 test).
    • Mixed reasoning.text + visible-text items in the same stream produce both thinking and text blocks in order.
    • reasoning_details arriving alongside tool_calls still routes through the buffered thinking path and preserves tool-call arguments (existing tests).
    • Non-array or unknown-type reasoning_details items are skipped silently.
  • What I did not verify:
    • Live OpenRouter run against real keys (no live lane invoked in this change).
    • Parallels smoke / cross-platform onboarding (not in scope for a parser-only fix).

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: a model intentionally using type: "text" inside reasoning_details for genuinely-hidden scratchpad content would now surface that content to users.
    • Mitigation: OpenRouter's documented semantics for response.output_text / response.text / text are visible assistant output; the existing reasoning.text type still maps to hidden reasoning. If a specific upstream deviates, follow-up can narrow the visible-type set.
  • Risk: Qwen3 regression from #66905 returns.
    • Mitigation: the existing Qwen3 regression test and the tool-call + reasoning_details test remain unchanged and still pass.

Testing notes

  • AI-assisted PR, lightly tested (parser unit tests only; no live OpenRouter run).
  • Exact tests run:
    • pnpm test src/agents/openai-transport-stream.test.ts (56/56 pass)
    • pnpm test src/agents/openai-transport-stream.test.ts -t reasoning_details (4/4 pass)
    • pnpm test src/agents/openai-transport-stream.test.ts -t visible-text (1/1 pass)
    • pnpm check (pre-existing aimock/server.ts failures on upstream/main; no new failures introduced)

Made with Cursor

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/openai-transport-stream.test.ts (modified, +138/-0)
  • src/agents/openai-transport-stream.ts (modified, +63/-14)
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

openclaw infer model run --model openrouter/z-ai/glm-5.1 --prompt "Reply with exactly: hello" --json 11:56:46 [agent/embedded] incomplete turn detected: runId=65e9308a-895d-4d68-b11f-07a042d2912f sessionId=65e9308a-895d-4d68-b11f-07a042d2912f stopReason=stop payloads=0 — surfacing error to user { "ok": true, "capability": "model.run", "transport": "local", "provider": "openrouter", "model": "z-ai/glm-5.1", "attempts": [], "outputs": [ { "text": "⚠️ Agent couldn't generate a response. Please try again.", "mediaUrl": null } ] }

Steps to reproduce

NOT_ENOUGH_INFO

Expected behavior

NOT_ENOUGH_INFO

Actual behavior

NOT_ENOUGH_INFO

OpenClaw version

最新版

Operating system

macOS Monterry 12.7.6

Install method

npm

Model

openrouter

Provider / routing chain

local

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

extent analysis

TL;DR

The issue with the OpenClaw infer model run may be related to the model or prompt configuration, and checking the model's capabilities and the prompt's format could help resolve the issue.

Guidance

  • Verify the model openrouter/z-ai/glm-5.1 is correctly configured and compatible with the OpenClaw version being used.
  • Check the prompt format "Reply with exactly: hello" to ensure it aligns with the expected input format for the model.
  • Review the OpenClaw documentation for any specific requirements or limitations related to model runs and prompts.
  • Consider testing the model with a different prompt to isolate if the issue is prompt-specific.

Notes

The provided information lacks specific details about the expected behavior, steps to reproduce, and additional context, making it challenging to provide a precise solution. Further investigation into the model, prompt, and OpenClaw configuration is necessary.

Recommendation

Apply workaround: Test the model with different prompts and configurations to identify the root cause of the issue, as the current information does not point to a specific version or configuration issue that would suggest an upgrade.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

NOT_ENOUGH_INFO

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: incomplete turn detected: runId=xxx sessionId=xxx stopReason=stop payloads=0 — surfacing error to user [3 pull requests, 2 comments, 3 participants]