Skip to content

fix(agent): Stop turn timeouts looking like cancelled failures - #1331

Merged
dcramer merged 9 commits into
mainfrom
fix/turn-deadline-user-visible
Aug 10, 2026
Merged

fix(agent): Stop turn timeouts looking like cancelled failures#1331
dcramer merged 9 commits into
mainfrom
fix/turn-deadline-user-visible

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

When a long turn hits the serverless time limit mid-tool, Junior already parks and auto-continues on the next function. The bug was the tool result left in history: it looked cancelled (isError, abort text), so the resumed model quit and narrated the timeout to the user.

What changed

Host-preempted tool attempts now use the normal tool-result field bash already has:

{ "target": "pnpm test", "timed_out": true }

timed_out is documented on the shared tool output schema. No invented outcome field, no cancelled/deadline jargon, isError: false.

What did not change

  • Auto-resume still owned by session state (resumeReason: "timeout")
  • Soft yields between tools still leave history alone
  • No history rollback, no silent re-run of the same tool

The model sees “this attempt timed out” the same way it already understands bash command timeouts, then keeps working.

Timeout resumes were still feeding the model cancelled/aborted tool text, so
it treated an internal execution-slice boundary as a user-visible failure.
Rewrite the aborted tool payload into an active-task continuation boundary.

Co-Authored-By: David Cramer <david@sentry.io>
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview Aug 10, 2026 2:57am

Request Review

@sentry-junior sentry-junior Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Stepping back on shape: this still looks like a prompt patch on a runtime boundary, not a durable contract.

The model-facing payload after this change still contains isError: true, aborted: true, exit_code: 130, cause: "turn_deadline", and scope: "execution_slice", plus instructional prose telling the model not to report the deadline. That keeps teaching the model our internal slice mechanics. The observed failure was the model narrating runtime vocabulary; this mostly swaps "cancelled" for a longer explanation that still names the deadline.

Compare the MCP auth pause path, which parks with a short placeholder (Authorization pending.) and does not expose runtime jargon. Timeout recovery is already owned by session state (resumeReason: "timeout"), so recovery does not need the tool result to look like a failed command or to include "don't tell the user" instructions.

I'd rather replace the aborted deadline tool result with a small canonical unknown-outcome projection, for example:

  • keep only what the model needs to know the prior attempt is unconfirmed (target, maybe outcome: "unconfirmed")
  • drop deadline/slice jargon from model-visible content
  • avoid instructional user-facing policy text in tool payloads
  • set isError only if something outside model interpretation actually depends on it; if nothing does, prefer not marking a recoverable park as an error

Also, the new unit test locks the instructional string (still active, without reporting the deadline). Prefer asserting the contract: no cancelled/deadline jargon in model-visible content, and the existing component/lifecycle continuation behavior still finishes the task.

I'm fine keeping the fix local to annotateTurnDeadlineToolResult, but the projection itself should be a clean boundary object, not a rewritten cancelled failure plus coaching text.

Replace cancelled/aborted tool text and runtime deadline jargon with a
small model-safe unconfirmed projection. Timeout recovery stays in session
state; tests assert the projection contract and continuation behavior.

Co-Authored-By: David Cramer <david@sentry.io>
@sentry-junior sentry-junior Bot changed the title fix(agent): stop turn-deadline aborts looking cancelled fix(agent): Project deadline aborts as unconfirmed outcomes Aug 8, 2026
@dcramer
dcramer marked this pull request as ready for review August 8, 2026 18:43
@github-actions github-actions Bot added the risk: medium PR risk score: medium label Aug 8, 2026
Call the model-facing boundary what it is: project an unconfirmed tool
result. Drop the old annotate/turn-deadline naming and simplify the
afterToolCall path so timeout recovery ownership is obvious.

Co-Authored-By: David Cramer <david@sentry.io>
Access aborted/target through a Record cast after the object guard so
prepare/typecheck no longer fails on Property 'aborted' does not exist.

@sentry-junior sentry-junior Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Final pass looks good to me.

The boundary is small and honest now: aborted deadline tool results become { outcome: "unconfirmed", target? } with isError: false, recovery stays on resumeReason: "timeout", and the old annotate/turn-deadline path is fully gone.

Naming and call site read cleanly, no leftover fallbacks or coaching prose, and the unit/component split matches the contract. I'd ship it.

Co-Authored-By: David Cramer <david@sentry.io>
Record mid-slice tool aborts as a plain timed_out attempt outcome so the
model knows the call did not finish, while host continuity stays on
session resume and automatic continuation.

Co-Authored-By: David Cramer <david@sentry.io>
@sentry-junior sentry-junior Bot changed the title fix(agent): Project deadline aborts as unconfirmed outcomes fix(agent): Project host-aborted tools as timed_out Aug 8, 2026
@sentry-junior sentry-junior Bot changed the title fix(agent): Project host-aborted tools as timed_out fix(agent): Stop turn timeouts looking like cancelled failures Aug 8, 2026
Drop the invented outcome: "timed_out" dialect. Host-preempted tool
attempts now project onto the same timed_out boolean bash already uses,
documented on the shared tool output schema.

Co-Authored-By: David Cramer <david@sentry.io>
Co-Authored-By: David Cramer <david@sentry.io>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9fb30e2. Configure here.

Comment thread packages/junior/src/chat/agent/index.ts Outdated
Keep finished sibling tool results intact after the host abort signal.

Co-Authored-By: David Cramer <david@sentry.io>
@dcramer
dcramer merged commit 1f13b13 into main Aug 10, 2026
42 checks passed
@dcramer
dcramer deleted the fix/turn-deadline-user-visible branch August 10, 2026 03:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant