microsoft / microsoft/amplifier

Bug: Dual content emission causes frontend truncation — content_block:end + token yield deliver same text twice

Open
#225 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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:

  1. Phase 1 (events): Iterates content blocks and emits content_block:start + content_block:end with full block text
  2. Phase 2 (yield): Re-yields the same response.text token-by-token as content_block:delta events

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:delta for observers), then emit content_block:end as a finalization signal (with metadata, not redundant content delivery)
  • Non-streaming fallback: Emit content_block:start + content_block:end with 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.