Summary
Gateway warm sessions can accumulate merged \n\n-joined user blobs in the model payload while platform inbound stays single-message per turn.
Observed behavior (reporter session 20260612_085708_c4403c61, 2026-06-12 weixin)
| Layer |
Evidence |
| Gateway inbound |
Single message each turn |
Agent turn_context |
history=N msg='…' single string |
AxonHub requests |
Last user content grows: 2 → 3 → … → 6 segments joined with \n\n |
| Alternation repair |
Repaired N message-alternation violations monotonically increasing |
Minimal repro segment 13:15–13:17 CST:
Cache eviction after ~1h idle was an amplifier, not the root cause (blob already 5 segments before evict).
Root cause chain
turn_context early-persists inbound user at turn start → _last_flushed_db_idx advances past pre-turn length.
- First API call runs
repair_message_sequence() which merges consecutive users (orphan + new) and shrinks messages in place.
- Flush cursor stays at the pre-compaction index → turn-end
_flush_messages_to_session_db computes flush_from past the first post-repair assistant row and skips persisting the assistant/tool chain.
- Next turn loads orphan user → new user → repair merges again → blob grows.
#44327 (reset _last_flushed_db_idx on cached-agent fresh turns) is necessary but not sufficient when step 2 compacts within the same turn.
Proposed fix
Community PR incoming from @JerryLiu369 fork.
Summary
Gateway warm sessions can accumulate merged
\n\n-joined user blobs in the model payload while platform inbound stays single-message per turn.Observed behavior (reporter session
20260612_085708_c4403c61, 2026-06-12 weixin)turn_contexthistory=N msg='…'single stringrequestsusercontent grows: 2 → 3 → … → 6 segments joined with\n\nRepaired N message-alternation violationsmonotonically increasingMinimal repro segment 13:15–13:17 CST:
last_msg_role=assistant, reply sent to WeChat; AxonHub request feat(agent): support full OpenRouter provider routing options #246 tail is correct (user → assistant → tool → assistant).turn_contexthistory count: 342 → 343 (+1 only) — only the inbound user row landed instate.db, not the assistant/tool chain.Cache eviction after ~1h idle was an amplifier, not the root cause (blob already 5 segments before evict).
Root cause chain
turn_contextearly-persists inbound user at turn start →_last_flushed_db_idxadvances past pre-turn length.repair_message_sequence()which merges consecutive users (orphan + new) and shrinksmessagesin place._flush_messages_to_session_dbcomputesflush_frompast the first post-repair assistant row and skips persisting the assistant/tool chain.#44327 (reset
_last_flushed_db_idxon cached-agent fresh turns) is necessary but not sufficient when step 2 compacts within the same turn.Proposed fix
repair_message_sequencecompacts the list, clamp_last_flushed_db_idxtolen(messages)._flush_messages_to_session_db, if cursor overshoots list length, fall back tostart_idx.Community PR incoming from @JerryLiu369 fork.