Skip to content

Give the Bot in the box the fix the other Bot got - #165

Merged
davidmckayv merged 2 commits into
mainfrom
fix/the-bot-in-the-box-answers-its-unanswered-calls
Aug 22, 2026
Merged

Give the Bot in the box the fix the other Bot got#165
davidmckayv merged 2 commits into
mainfrom
fix/the-bot-in-the-box-answers-its-unanswered-calls

Conversation

@davidmckayv

Copy link
Copy Markdown
Contributor

A gap in #147, found by driving the release candidate.

What was still broken

A declined take-the-wheel leaves an assistant message holding a tool call that nothing ever answers, and every later turn in that thread dies at the provider:

400 An assistant message with 'tool_calls' must be followed by tool messages responding to
each 'tool_call_id'. The following tool_call_ids did not have response messages: call_l1PNce...

#147 fixed that in agent-langgraph. Only there. agent-bot is the Bot that ships in the box and the one behind the Browser Bot, it builds its history in its own function, and it went on failing in exactly the same way.

So the fix landed on the Bot fewer people meet, and the one a person meets first still destroyed the conversation. It showed up in red across the top of the transcript while driving the release candidate.

The fix

Same treatment, against this Bot's provider shape: collect which tool_call_ids were ever answered, and for any that were not, append a tool result immediately after the assistant message that made the call — position matters, an answer at the end of the history fixes nothing.

It says the truth rather than a fake success, so the Bot does not report work it never did.

The wording moves to shared/bot-prompt.ts, which both Bots already import for COMPUTER_GUIDANCE. Two implementations telling a model different things about the same situation is precisely how this happened. agent-langgraph/src/history.ts re-exports it, so its tests and callers are unchanged.

The function moves to agent-bot/src/history.ts for the reason the other one did: index.ts calls serve() at module scope, so a test importing it to reach one pure function binds a port.

Driven in Chrome, on a rebuilt container

New chat → "Open https://github.com/settings/profile and read my display name." → GitHub sign-in wall, help request raised → declined by sending something else:

Before After
"Never mind. What is 17 times 3?" red 400 banner, no answer 17 × 3 = 51. "Source: mental arithmetic; I did not look this up."
"Did you ever manage to read my GitHub display name?" red 400 banner "No. I opened https://github.com/settings/profile, but it redirected to GitHub's sign-in page, so I could not read your display name."

Three turns, all alive, and it does not claim a result it never got. The provenance rule from #153 is visible in the same answer, unprompted.

Tests

agent-bot/tests/history.test.ts, five cases mirroring the other Bot's:

  • an unanswered call is answered, so the next turn is not refused outright
  • it says no result rather than inventing a successful one
  • it lands directly after the assistant message that made it
  • a call that was answered keeps its real answer and gains nothing
  • several unanswered calls in one message each get their own answer

Three of the five fail with the fix disabled. Full suite 1204 passing, lint, format and typecheck clean.

agent-bot has no tests directory before this and is not typechecked in CI — worth its own look, but not folded in here.

A declined take-the-wheel leaves an assistant message holding a tool call
that nothing ever answers, and every later turn in that thread dies at
the provider with "an assistant message with 'tool_calls' must be
followed by tool messages responding to each 'tool_call_id'".

That was fixed in agent-langgraph and only there. agent-bot is the Bot
that ships in the box and the one behind the Browser Bot, it builds its
history in its own function, and it went on failing in exactly the same
way. Driving the release candidate put the error on screen in red, on the
Bot a person meets first.

Same treatment: unanswered calls are answered when the history is built,
immediately after the assistant message that made them, with the truth
rather than a fake success.

The wording moves to shared/bot-prompt.ts, which both Bots already import,
because two implementations telling a model different things about the
same situation is how this happened. agent-langgraph re-exports it so its
own tests and callers are unchanged.

The function moves to agent-bot/src/history.ts for the reason the other
one did: index.ts calls serve() at module scope, so a test that imports it
to reach one pure function binds a port.

Driven in Chrome on a rebuilt container. New chat, ask for a GitHub page
behind a sign-in, decline the handover, and the conversation carries on:
17 x 3 = 51, then an honest "No. I opened it, but it redirected to
GitHub's sign-in page, so I could not read your display name." Before
this, the red 400 banner and nothing else, for every message after.
@davidmckayv
davidmckayv merged commit 6507bb4 into main Aug 22, 2026
@davidmckayv
davidmckayv deleted the fix/the-bot-in-the-box-answers-its-unanswered-calls branch August 22, 2026 16:21
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