Skip to content

fix(claude): close dangling tool calls with aborted results - #69

Open
Drix10 wants to merge 2 commits into
skillsynchq:mainfrom
Drix10:fix/claude-close-dangling-tool-calls
Open

Drix10 wants to merge 2 commits into
skillsynchq:mainfrom
Drix10:fix/claude-close-dangling-tool-calls

Conversation

@Drix10

@Drix10 Drix10 commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Issue: #68

What changed and why?

messages_to_records (shared by Claude Code and Cowork) exported unanswered
tool_use blocks verbatim. One Ctrl+C mid-tool therefore poisoned the whole
resumed session: the Anthropic API 400s on the first tool_use without a
tool_result immediately after it.

A new close_dangling_calls pass, next to lower_artifact_messages, and
after it so artifact pairs aren't doubled — appends one aborted error result
("Tool execution was interrupted or cancelled.", is_error) per dangling
call as a final user turn. Slash-command calls are excluded: their output
rides local_command lines, where a synthesized tool_result would itself
be rejected. Reused ids close only the occurrences left open, and a result
recorded before its call (Codex web-search order) already answers it, so it
holds as credit instead of drawing a duplicate.

Tests: five in tests/integration/claude_code.rs, the dangling call closes
as an error with paired calls untouched (failed on main before the fix),
id-reuse scoping, every open call in one turn closing together, no duplicate
for results recorded before their call (Codex web-search order), and
command-call exclusion. Docs: one caveat bullet in
docs/formats/claude-code.md, matching the existing list style.

Checks: cargo test -p txcript --test integration (212 passed, default
features), cargo fmt --check and cargo clippy -p txcript --all-targets
(zero warnings) — run under the GNU toolchain, CI's MSVC run will confirm.

@NishantJoshi00

Copy link
Copy Markdown
Collaborator

If an interrupted tool call is followed by more conversation, its synthetic result lands at the end. Claude requires the result immediately after the call. Can we insert it there and test an interruption followed by another user turn?

@Drix10

Drix10 commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Done. The result now goes right after the turn that opened the call instead of at the end, so mid-transcript interruptions pair up too. Matching is per-occurrence. Also sorted the inserts since map order isn't stable across runs.

This branch has not been deployed

No deployments
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.

2 participants