Skip to content

core: standalone signed-empty reasoning turns are replayed into later requests #46881

Open

Description

@bbartels

Description

V2 replays completed assistant turns whose only content is empty reasoning plus provider metadata.
In packages/core/src/session/runner/to-llm-message.ts, same-model reasoning retains provider metadata, and the meaningful filter considers metadata sufficient even when part.text === "". The existing omits empty assistant turns test explicitly preserves a standalone { text: "", state: { signature } } turn.
The Amazon Bedrock adapter serializes each retained part as:
{
"reasoningContent": {
"reasoningText": {
"text": "",
"signature": "..."
}
}
}
Controlled forks isolated the effect:

  • The exact prompt with the clean full history (~620k provider tokens) produced visible text and tools.
  • The same prompt with one or two standalone signed-empty turns still worked.
  • The same prompt with five accumulated signed-empty turns deterministically returned another signature-only end_turn with no visible output.
  • Manual compaction repaired the session because compaction rendering drops empty reasoning parts.
    Expected: signed reasoning state is retained when it accompanies semantic assistant output—text, readable reasoning, or a tool call—but a standalone metadata-only assistant turn is omitted from future model history or marked failed by the no-output handling described separately.
    Actual: state-only turns accumulate and can poison subsequent same-model requests.

Plugins

No response

OpenCode version

opencode2 v0.0.0-dev-18900; current V2 source af332a2 remains affected.

Steps to reproduce

  1. Create a V2 session using a provider that returns signed reasoning metadata.
  2. Persist several completed assistant turns containing only reasoning.text = "" and a provider signature.
  3. Submit a prompt that works in a fork before those turns.
  4. Observe the provider request replay each empty reasoningText plus signature.
  5. Observe the later response repeat the signature-only pattern.
  6. Compact the same session and retry; the prompt works because the empty reasoning turns are no longer replayed.

Screenshot and/or share link

No response

Operating System

No response

Terminal

No response

Activity

  1. github-actions commented on Sep 2, 2026

    @github-actions
    Contributor

    This issue might be related to existing issues about empty or incomplete assistant turns being replayed to providers. Please check:

    Your issue focuses specifically on signed empty reasoning turns (Bedrock provider metadata/signature accumulating across turns), which appears to be a distinct variant of the broader empty-assistant-turn replay problem. Linking these in case the fix should be coordinated.

  2. Rocklis commented on Sep 4, 2026

    @Rocklis

    Confirmed on current dev. The existing toLLMMessages test actually preserves a standalone empty reasoning part when it has a provider signature, so the reported history shape is reproducible without a live Bedrock call.

    I have a small replay-side fix: provider metadata is kept when the same assistant turn also contains real text or a tool call, but a turn containing only empty reasoning metadata is omitted. The full packages/core suite passes (1,097 tests); I'll open the PR next.

  3. bbartels commented on Sep 4, 2026

    @bbartels
    ContributorAuthor

    not sure what the relation between dev/v2 are, but I was using v2

  4. Rocklis commented on Sep 4, 2026

    @Rocklis

    Yep, that is the path this fix targets. dev is just the repository branch I tested against; the affected replay code lives in the V2 packages/core path. The fix is in #47357.

  5. Rocklis commented on Sep 7, 2026

    @Rocklis

    I've moved #47357 onto v2 (3079fb4) and rerun the 24 replay tests there. My earlier full-suite result was from dev, not v2; the PR description now makes that distinction.

    @bbartels, could you try this head with the session that accumulated signature-only turns? The change drops standalone empty reasoning turns, but keeps the signature when the same turn has text or a tool call.

  6. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed write-up and the forked-session comparison.

    The replay is confirmed in code on the latest dev (35a4a68). In packages/core/src/session/runner/to-llm-message.ts, the meaningful filter keeps a reasoning part with empty text when it has provider metadata, so a turn that holds only an empty reasoning part with a signature is sent again on later same-model requests. The existing test omits empty assistant turns expects that turn to be kept, so the replay is deliberate today.

    What would make it a bug is how Bedrock reacts once several of these turns pile up: signature-only replies with no visible output. That needs a real Bedrock account and a long session, and the sandbox I reproduce in has no provider credentials. A mock can't show how the real model responds, so a maintainer with Bedrock access will need to confirm it.

    Related:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions