[Bug] OpenClaw plugin assemble() produces consecutive user turns after archive commit — causes empty responses from Gemini/Anthropic
Summary
After an OpenViking session archive commit, buildAssembledContext() in the OpenClaw context-engine plugin produces multiple consecutive user-role messages. This violates the strict alternating turn ordering required by Gemini and Anthropic APIs, causing stopReason=stop payloads=0 (empty model response) on every subsequent turn until the session is manually deleted.
Reproduction
- Send ~30-40 messages to an OpenClaw agent (Gemini Pro) with the OpenViking context-engine plugin active
- Wait for
commitTokenThreshold to trigger automatic commit(wait=false) with archived=true
- Send another message after archive completes
- Agent returns:
⚠️ Agent couldn't generate a response. Please try again.
- Every subsequent message fails identically — the session is permanently broken
Root Cause
buildArchiveMemory() (context-engine.ts) creates archive context as role: "user" messages:
messages.push({ role: "user", content: `[Session History Summary]\n${archiveOverview}` });
messages.push({ role: "user", content: `[Archive Index]\n${lines.join("\n")}` });
buildAssembledContext() concatenates archive + session messages:
const assembled = [...archive.messages, ...session.messages];
After archive, if session.messages is empty or starts with a user message, the assembled array becomes:
user: [Session History Summary]...
user: [Archive Index]...
user: <new message>
Three consecutive user turns. sanitizeToolUseResultPairing() repairs tool-use/result pairing but does NOT merge consecutive user turns. mergeConsecutiveAssistants() exists for assistant turns but has no user counterpart.
The OpenClaw SDK provides validateGeminiTurns() and mergeConsecutiveUserTurns() in pi-embedded-helpers/turns.js, but the OV plugin does not call them, and the OC runtime only calls validateGeminiTurns in the replay path.
Gateway Log Pattern
openviking: committed session=XXX, status=accepted, archived=true
openviking: assemble entering session content for XXX: [{"role":"user","content":"[Session History Summary]..."},{"role":"user","content":"..."}]
empty response detected: runId=XXX provider=google/gemini-3.1-pro-preview — retrying 1/1
empty response retries exhausted: runId=XXX attempts=1/1
incomplete turn detected: runId=XXX stopReason=stop payloads=0 — surfacing error to user
Suggested Fix
Add mergeConsecutiveUsers() analogous to mergeConsecutiveAssistants(), call after sanitizeToolUseResultPairing().
Environment
- OpenClaw: 2026.4.24, OpenViking: v0.3.12, Plugin: @openclaw/openviking@2026.4.34
- Provider: Google Gemini 3.1 Pro
Workaround
Delete the session file and restart gateway. Recurs after next archive commit.
[Bug] OpenClaw plugin assemble() produces consecutive user turns after archive commit — causes empty responses from Gemini/Anthropic
Summary
After an OpenViking session archive commit,
buildAssembledContext()in the OpenClaw context-engine plugin produces multiple consecutiveuser-role messages. This violates the strict alternating turn ordering required by Gemini and Anthropic APIs, causingstopReason=stop payloads=0(empty model response) on every subsequent turn until the session is manually deleted.Reproduction
commitTokenThresholdto trigger automaticcommit(wait=false)witharchived=true⚠️ Agent couldn't generate a response. Please try again.Root Cause
buildArchiveMemory()(context-engine.ts) creates archive context asrole: "user"messages:buildAssembledContext()concatenates archive + session messages:After archive, if
session.messagesis empty or starts with ausermessage, the assembled array becomes:Three consecutive
userturns.sanitizeToolUseResultPairing()repairs tool-use/result pairing but does NOT merge consecutive user turns.mergeConsecutiveAssistants()exists for assistant turns but has nousercounterpart.The OpenClaw SDK provides
validateGeminiTurns()andmergeConsecutiveUserTurns()inpi-embedded-helpers/turns.js, but the OV plugin does not call them, and the OC runtime only callsvalidateGeminiTurnsin the replay path.Gateway Log Pattern
Suggested Fix
Add
mergeConsecutiveUsers()analogous tomergeConsecutiveAssistants(), call aftersanitizeToolUseResultPairing().Environment
Workaround
Delete the session file and restart gateway. Recurs after next archive commit.