Skip to content

Stop the tool-call repair recursing into itself - #63

Merged
davidmckayv merged 1 commit into
mainfrom
fix/repair-history-recurses
Aug 20, 2026
Merged

Stop the tool-call repair recursing into itself#63
davidmckayv merged 1 commit into
mainfrom
fix/repair-history-recurses

Conversation

@davidmckayv

Copy link
Copy Markdown
Contributor

What this changes

repairUnansweredToolCalls takes an id source so tests can make ids predictable:

newId: () => string = () => newId(),

Inside that default, newId resolves to the parameter, not the import on line 2. The default
calls itself until the stack goes. Introduced by #62.

It hangs exactly when the function does its job. The parameter is only invoked on the repair branch,
reached when there is an unanswered tool call, and the one real caller
(channel-chat.tsx L228) omits the argument. Every existing test passes its own ids, so no test ever
ran the default.

Renamed the parameter so it cannot shadow the import, and added a test that calls it the way the
real caller does.

Found by @guidovizoso. Biome had flagged it too, as noUnusedImports on line 2, which I waved
through as a warning when I made the change.

Where it runs

  • New state that outlives a request? None. A pure function over a message array.
  • What happens on the second replica? Identical; nothing is held.
  • Anything serialised? N/A.
  • Anything fanned out to a browser? No.
  • New listener, port, or schedule? No.

Boundary and audit

  • N/A. No gateway, policy, or audit path touched.

Changelog

Proof

The new test fails on the old code by hanging rather than by asserting, which is the honest
reproduction. 745 tests pass, biome check clean on both files, typecheck clean.

`repairUnansweredToolCalls` took an id source named `newId` defaulting to
`newId()`. Inside the default, `newId` resolves to the parameter, not the
import, so the default calls itself until the stack goes.

It hangs exactly when the function does its job: the parameter is only invoked
on the repair branch, and the one real caller omits the argument. Every test
passed its own ids, which is why no test ran the default and why this survived.

Renamed so it cannot shadow the import, and there is now a test that calls it
the way the real caller does, with the argument left out.

Found by Guido Vizoso. Biome had said so too, as an unused import on line 2,
which I had waved through as a warning.
@davidmckayv
davidmckayv merged commit f8885b6 into main Aug 20, 2026
3 checks passed
@davidmckayv
davidmckayv deleted the fix/repair-history-recurses branch August 20, 2026 22:55
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