Skip to content

fix: preserve context after successful assistant retry#498

Open
thekfjie wants to merge 2 commits into
DEEIX-AI:devfrom
thekfjie:fix/retry-context-preservation
Open

fix: preserve context after successful assistant retry#498
thekfjie wants to merge 2 commits into
DEEIX-AI:devfrom
thekfjie:fix/retry-context-preservation

Conversation

@thekfjie

@thekfjie thekfjie commented Jul 18, 2026

Copy link
Copy Markdown

Summary

Fix default-branch context truncation after a failed generation is recovered by retrying the assistant response.

  • Treat an errored user message as recovered only when the next message in the active ancestor chain is a usable assistant retry.
  • Require the retry assistant to point to that user, have branch_reason=retry, have a source_message_id, and be success or interrupted.
  • Promote only the in-memory message copy before context normalization. This restores transcript and attachment context for existing affected conversations without rewriting historical rows or requiring a migration.
  • Keep genuinely failed tails, canceled responses, failed retries, and unrelated messages excluded from default context.

Reproduction

  1. Start with a conversation that already has substantial successful history, optionally including attachments.
  2. Send the next user message and let generation fail before any reply is retained. The user and assistant rows are finalized as error.
  3. Retry the failed assistant response. Assistant retry reuses the original user row and persists a new successful assistant child.
  4. Send another message through the default branch.

The active path is now:

successful history
  -> user (error)
    -> assistant retry (success, source_message_id set)

Actual behavior

selectLatestDefaultParentCandidate correctly selects the successful retry assistant, but normalizeDefaultBranchContext walks backward, sees the reused user still marked error, and treats it as a hard boundary. Earlier transcript and attachment context are discarded.

In a sanitized affected trace, the next request contained only 776 input tokens plus 4,070 cache-read tokens (4,846 total), while retrying the same message with its full branch produced 64,704 total input tokens.

Expected behavior

A successful or retained interrupted assistant retry makes its reused user turn valid context. The next default message should keep the complete active ancestor chain and its attachments.

Root cause and approach

Assistant retry intentionally creates only a new assistant branch message and does not change the reused user row. The default context normalizer previously evaluated every message independently, so the stale user error state split an otherwise recovered branch.

The fix recognizes this specific two-message relationship during normalization and changes only a copied message slice. Doing this at read time also repairs already affected conversations; changing only the retry persistence path would protect new retries but leave existing conversations truncated.

Change type

  • Bug fix
  • Feature
  • Documentation
  • Refactor
  • Configuration / deployment
  • Security hardening
  • Other

Affected areas

  • Frontend / UI
  • Backend / API
  • Authentication / authorization
  • Conversations / streaming
  • Files / RAG / extraction
  • Model routing / providers
  • MCP / tools
  • Billing / payments
  • Admin console
  • Deployment / Docker / configuration
  • Documentation

Verification

  • go test ./internal/application/conversation -count=1
  • go test -race ./internal/application/conversation -count=1
  • go test ./internal/application/... -count=1
  • go test ./... -count=1
  • go vet ./...
  • Regression coverage verifies complete history, historical attachments, and attachments on the retried user remain available.
  • Boundary coverage verifies successful and interrupted retries recover context, while failed retries, non-retry assistants, missing sources, mismatched parents, and already-successful users are not promoted.

Screenshots, API examples, or logs

No UI change. The reproduction and token counts above are sanitized; no conversation content, identifiers, credentials, or user data are included.

Configuration, migration, and compatibility notes

  • No database migration or data rewrite.
  • No configuration, API contract, routing, billing, or deployment change.
  • Existing affected conversations recover on their next default send because normalization occurs at read time.

Documentation

  • Documentation is not needed for this internal bug fix.
  • Documentation was updated.
  • Documentation still needs to be updated.

Security and privacy

  • No secrets, tokens, credentials, local config, or personal data are included.
  • User data access remains scoped by authenticated user context unless an admin-only path explicitly requires broader access.
  • Security-sensitive behavior was reviewed, including authentication, authorization, provider routing, file processing, billing, and admin APIs where relevant.

Checklist

  • I searched existing issues and pull requests; no duplicate report or fix was found.
  • Changes are focused and do not include unrelated refactors.
  • Tests or static verification were run where practical.
  • User-facing behavior, deployment steps, API contracts, or configuration changes are documented.
  • Generated artifacts are included only when this project explicitly requires them.
  • Caches, build output, .pyc files, .env files, and local storage data are not committed.

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.

1 participant