Skip to content

fix(copilot): let a chat interrupted mid tool call resume - #43

Merged
alanshen27 merged 1 commit into
mainfrom
devin/1785916424-resume-interrupted-chat-runs
Aug 5, 2026
Merged

fix(copilot): let a chat interrupted mid tool call resume#43
alanshen27 merged 1 commit into
mainfrom
devin/1785916424-resume-interrupted-chat-runs

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

A run killed mid-tool (deploy, OOM, cancelled stream, dead worker) stores an assistant turn whose tool part has no result — and half-written parts can also miss fields their state requires (output-error with no errorText, output-available with no output). That message then failed validateUIMessages on every subsequent send, and the route reported it as "Copilot unavailable. Run pnpm db:generate…", so the channel stayed stuck until the bad message aged out of the 500-message window.

Two new pieces in lib/copilot/messages.ts:

// A tool call is only replayable as a call/result pair, so anything without a
// recorded result becomes an errored result the model can read and retry.
repairInterruptedToolParts(messages)   // input-streaming | input-available | approval-*
                                       // | malformed terminal part  ->  output-error
                                       // tool part with no toolCallId -> dropped

validateResumableUIMessages(raw)       // repair -> validate; on failure, validate
                                       // message-by-message and keep what survives

validateResumableUIMessages replaces validateUIMessages on every path that reads a stored or client transcript: POST /api/ai/chat, executeChatRun, the dead-attempt takeover, stale-run expiry, and chat.persistMessages. A single unusable message can no longer block the whole channel.

Model-side, sanitizeUiMessagesForModel now repairs before filtering, so an interrupted call reaches the model as a failed tool result instead of silently vanishing from the transcript. stripOrphanToolResults is the mirror of the existing stripOrphanToolCalls (a result whose call fell out of the window is just as invalid); pairToolCallsWithResults applies both wherever the converted prompt is built.

Link to Devin session: https://app.devin.ai/sessions/27a2860693d444f8a9a37442a83762d7
Requested by: @alanshen27

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@alanshen27 alanshen27 self-assigned this Aug 5, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@alanshen27
alanshen27 merged commit 02f5491 into main Aug 5, 2026
1 check failed
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