microsoft / microsoft/amplifier
Bug: Dual content emission causes frontend truncation — content_block:end + token yield deliver same text twice
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 3.1k
- Forks
- 261
- Avg merge
- 3h 28m
- Merged PRs (30d)
- 13
Description
Summary
The loop-streaming orchestrator emits the same response text through two redundant pipelines, causing downstream consumers that read both channels to accumulate duplicated content.
Reproduction
When extended thinking with interleaved content is enabled (interleaved-thinking-2025-05-14), the orchestrator:
- Phase 1 (events): Iterates content blocks and emits
content_block:start+content_block:endwith full block text - Phase 2 (yield): Re-yields the same
response.texttoken-by-token ascontent_block:deltaevents
Frontend consumers that handle both content_block:end (writing full text to message.content) and delta events (appending tokens to message.content) end up with message.content longer than the actual response. In the observed case: 2,009 chars of actual content inflated to 2,121 chars in message.content.
Impact
The Kepler desktop frontend has a liveTextTail guard in ChatMessage.tsx that detects the mismatch between contentParts text and message.content length, then creates a phantom tail fragment. The user sees only the last ~112 characters of a full response (starting mid-word), with the rest hidden behind tool call timeline entries.
Observed: User asked for dashboard KPI recommendations. Full response was 2,009 chars with tables and analysis. User saw only: "d I'll start there. Also happy to hear if you have other specific KPIs or filters in mind that I haven't listed."
Expected Behavior
Each content block should be delivered through one channel, not both:
- Streaming mode: Yield tokens (with
content_block:deltafor observers), then emitcontent_block:endas a finalization signal (with metadata, not redundant content delivery) - Non-streaming fallback: Emit
content_block:start+content_block:endwith full content
Architectural Note
Per the amplifier-core design philosophy ("Explicit > implicit", "No hidden state"), consumers should not need to deduplicate content from the orchestrator. The orchestrator owns delivery policy and should own delivery correctness.
Workaround
Kepler desktop is applying a temporary frontend guard: only create liveTextTail during active streaming (message.isStreaming === true), not for finalized messages.
Environment
- amplifier-module-loop-streaming (latest via git)
- amplifier-module-provider-anthropic with interleaved thinking enabled
- Kepler desktop sidecar (amplifier-distro-kepler)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the loop-streaming orchestrator's content-block iteration and response.text yield paths, using the interleaved-thinking-2025-05-14 reproduction described in the issue. Compare the content delivered through content_block:end with content_block:delta, and review the affected ChatMessage.tsx behavior. Done means streaming delivers text once while content_block:end remains only a finalization signal, with the non-streaming fallback retaining full content.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- stream-processing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100