Skip to content

fix: filter delivery-mirror from all consumer paths (LLM context, webchat, API)#223

Open
BingqingLyu wants to merge 2 commits into
mainfrom
fork-pr-40716-fix-filter-delivery-mirror-from-context
Open

fix: filter delivery-mirror from all consumer paths (LLM context, webchat, API)#223
BingqingLyu wants to merge 2 commits into
mainfrom
fork-pr-40716-fix-filter-delivery-mirror-from-context

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Problem

Internal delivery-mirror audit entries (provider=openclaw, model=delivery-mirror) leak into all three consumer paths, causing escalating duplicate assistant messages that degrade over the life of a session:

Fixes openclaw#33263, openclaw#38061, openclaw#39469.
Related: openclaw#30316, openclaw#39795.

Note: Other open PRs (openclaw#38075 etc.) only filter chat.history. This PR covers all three consumer paths — including LLM context (the most impactful) and the sessions API.

Changes

Path File What
LLM context tool-result-context-guard.ts Filter via shared predicate in transformContext pipeline
Webchat UI chat.ts Filter before slice/byte-budget so audit entries don't consume the bounded window
API sessions.ts Filter in sessions.get handler
Predicate transcript.ts New isDeliveryMirrorMessage() using in narrowing (zero type assertions)

The write path is intentionally unchanged — delivery-mirror entries remain in session JSONL as an audit trail. appendCustomEntry() was investigated but SessionManager._persist() defers writes until a type:"message" + role:"assistant" entry exists, making it unreliable for standalone entries. Existing session files already contain old-format entries, so consumer-side filters are needed regardless.

Tests

7 new tests across 2 files covering the predicate (positive match, role/provider/model mismatches, non-object input) and the transformContext integration (strips delivery-mirror; preserves array identity when none present).

Unrelated

Commit f5c618eb fixes a pre-existing oxfmt formatting issue in src/cli/daemon-cli/lifecycle.test.ts.

kiyoakii added 2 commits March 9, 2026 23:18
…PI responses

delivery-mirror entries (provider=openclaw, model=delivery-mirror) are internal
cross-channel delivery audit records written by
appendAssistantMessageToSessionTranscript(). They use appendMessage() which
creates type:"message" entries indistinguishable from real LLM responses,
causing them to leak into buildSessionContext() and API responses.

This causes duplicate assistant messages in the LLM context window (escalating
from 2x to 6-8x over a session), duplicate renders in webchat UI, and raw
audit entries in API responses.

Fix: filter delivery-mirror messages at the three consumer points:
- transformContext pipeline (LLM context)
- chat.history handler (webchat UI)
- sessions.get handler (API)

Add isDeliveryMirrorMessage() predicate co-located with the write path in
transcript.ts. Add regression tests for all filter paths.

The write path (appendMessage) is intentionally unchanged - delivery-mirror
entries remain in the JSONL as an audit trail. appendCustomEntry() was
considered but _persist() in SessionManager defers writes until an assistant
message exists, making it unreliable for standalone audit entries.

Fixes openclaw#33263, openclaw#38061, openclaw#39469
Related: openclaw#30316, openclaw#39795
- Move delivery-mirror filter before slice/byte-budget in chat.history
  so internal entries do not consume bounded window slots
- Drop unnecessary .toLowerCase() on role check for consistent
  strict equality across all three predicate fields
- Add symmetric test case for model match with provider mismatch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Webchat duplicates assistant replies via delivery-mirror transcript entry

2 participants