Skip to content

Preserve complete stopped responses and cancel unfinished tools - #8259

Merged
Sg312 merged 1 commit into
stagingfrom
fix/staging-stop-terminal-replay
Sep 24, 2026
Merged

Sg312 merged 1 commit into
stagingfrom
fix/staging-stop-terminal-replay

Conversation

@Sg312

@Sg312 Sg312 commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stop could mistake a contiguous Redis prefix for the full response and persist it before the run owner flushed its tail. Replay now requires the actor's matching chat/run, a terminal run status, and contiguous events through the final completion event. Active, missing, mismatched, and incomplete runs defer to their canonical finalizer.

Stopped responses also mark unfinished tools cancelled, including when a cancelled completion block already exists. This closes the persistence findings from #8257 while retaining its identifiers-only Stop request and queued-edit protection.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other

Testing

  • 178 Stop, queued-send, persistence, abort, and authorization regressions passed before adding two explicit immutable tool-cancellation cases; all 56 persistence tests passed after those additions.
  • App type checking, Biome, and API validation audit pass.
  • Regression cases cover an 11 MiB response, unfinished contiguous replay, mismatched or active runs before any Redis read, and cancelled tools after reload.
  • Browser automation is unavailable because its runtime exits during initialization.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Sep 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Sep 24, 2026 7:40pm UTC

Request Review

@Sg312
Sg312 merged commit 491740a into staging Sep 24, 2026
24 checks passed
@greptile-apps

greptile-apps Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

The PR should not merge until stopped persistence cancels every nonterminal tool state and the import follows the repository requirement.

Findings

  1. P1 Stopped tools remain unfinished ▶
  2. P1 Late title event blocks replay ▶
  3. P2 New import violates path rule ▶

Summary

The PR restricts stopped-response replay to a matching terminal run with a contiguous event history ending in completion, and marks executing tools cancelled in persisted stopped messages.

  • Adds route and persistence regressions for incomplete replay and tool cancellation.
  • Cancellation still misses other supported nonterminal tool states.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Stop[Stop request] --> Snapshot{Client snapshot?}
  Snapshot -->|No| Gate[Matching terminal run]
  Snapshot -->|Yes| Finalizer[Turn finalizer]
  Gate --> Replay{Contiguous through completion?}
  Replay -->|Yes| Finalizer
  Replay -->|No| Owner[Defer to run owner]
  Finalizer --> Persist[Persist stopped message]
Loading

Reviews (2) · Last reviewed commit: "Finalize stopped replay only after the o..."

const contentBlocks = message.contentBlocks ?? []
const contentBlocks = (message.contentBlocks ?? []).map(
(block): PersistedContentBlock =>
block.toolCall?.state === 'executing'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Waiting tools remain active

If Stop arrives while a tool is awaiting approval, this check leaves it unchanged because it only cancels executing tools. Replay preserves the awaiting_approval state, so the stopped turn can still show an actionable permission card after reload. Cancel the other unfinished tool states as well.

/** StreamWriter starts at 1; Redis may trim oldest events or skip corrupt entries. */
if (events.length === 0 || !events.every((event, index) => event.seq === index + 1)) return null
if (
events.at(-1)?.type !== 'complete' ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Late title event blocks replay

On a first turn, title generation runs independently and can publish a session event after the run's complete event. This check then rejects a complete, gap-free replay. If the owner's message save failed and an identifiers-only Stop retries persistence, the retry returns success without saving the response. The completion check needs to allow later side-effect events.

@waleedlatif1
waleedlatif1 deleted the fix/staging-stop-terminal-replay branch September 24, 2026 19:49
const contentBlocks = message.contentBlocks ?? []
const contentBlocks = (message.contentBlocks ?? []).map(
(block): PersistedContentBlock =>
block.toolCall?.state === 'executing'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Stopped tools remain unfinished When a stopped turn contains a pending or awaiting_approval tool, this check leaves its state unchanged while the message gets a cancelled completion block. Both states can survive result persistence or replay, so reloaded history can show a stopped tool as still pending or awaiting approval. Cancel those nonterminal states as well as executing.

normalizeMessage,
type PersistedMessage,
stripToolResultOutput,
withStoppedContentBlock,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 New import violates path rule The added withStoppedContentBlock import uses the relative ./persisted-message path. The repository requires absolute imports in apps/sim; change this import to an @/ path before merging.

Context Used: Import patterns for the Sim application (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

This branch was previously deployed

1 inactive deployment
Preview — d5b26f4e Deployed Sep 24, 2026 by vercel[bot]
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