Skip to content

fix(repl): keep a dropped reply's tool work; start and answer in more setups - #222

Merged
fuseraft merged 1 commit into
mainfrom
fix/repl-keep-tool-work-on-discarded-reply
Nov 13, 2026
Merged

fuseraft merged 1 commit into
mainfrom
fix/repl-keep-tool-work-on-discarded-reply

Conversation

@fuseraft

Copy link
Copy Markdown
Owner

Four REPL bugs found while live-testing file change tracking. Each one was reproduced on main and fixed here.

A dropped reply took the turn's tool work with it

When the REPL drops a reply (empty, or taken for leaked tool text), it retries the turn with a correction message. The turn's tool calls and results were only added to history when a reply was kept, so the retry started without them. The model didn't know its tools had already run, and ran them again.

Live, the model was asked to run echo run >> log.txt and then reply with only the tool's [OK] line, which gets the reply dropped:

Build Model shell_run calls Lines in log.txt
main Claude Sonnet 5.5 2 2
this branch Claude Sonnet 5.5 1 1
main Grok 4.7 2 2
this branch Grok 4.7 1 1

The completed calls and results now stay in history, closed with a "[Turn stopped before a final answer: …]" note. This happens before the retry, and again when the REPL gives up after a second dropped reply. It reuses CompletedRounds, the same way an interrupted turn keeps its finished work.

Answers quoting a tool error were dropped

The #119 check drops a reply when most of its characters are on [OK]/[ERROR] lines. A model quoting a refused write to the user ("The tool refused the write. Its exact error message was:" followed by the error in a code block) was dropped as a leak. Lines inside a code fence no longer count. The #119 cases aren't fenced, so they're still caught.

Where-is questions failed on Anthropic thinking models

For a where-is question, the REPL forces a tool call. Sonnet 5.5 rejects that ("tool_choice: type "tool" and "any" are not supported for this model"), so the turn failed. If the provider rejects the forced tool_choice before anything streams, the request is now sent again without forcing. Models that accept forcing (Grok) are unchanged.

--vscode --model wouldn't start with a settings-only config

--model plus FUSERAFT_API_KEY is meant to be a complete setup. But once ~/.fuseraft/config existed without a model, which is the state after fuseraft settings set or the VS Code settings panel on a fresh install, the REPL refused to start with "fuseraft is not configured". --model now fills in a config that has no model, for that run only. A configured model is left alone, and nothing is saved.

Tests

New tests in ReplLimitsTurnTests, ReplTurnSanitizeAssistantResponseTests and ReplCommandTests. Each fails with its fix reverted. The live runs used the JSON bridge, the mode VS Code and the web app use.

… setups

- A reply the REPL dropped (empty, or taken for leaked tool text) took
  the turn's tool calls and results with it, so the retry ran them
  again without knowing: live, `echo run >> log.txt` ran twice. The
  completed calls and results now stay in history, closed with a note,
  before the retry and when it gives up.
- An answer quoting a tool's [ERROR] or [OK] line in a code fence was
  dropped as leaked tool text. Fenced lines no longer count as leaked.
- Anthropic's thinking models refuse a forced tool call, so a
  where-is question failed outright on Sonnet 5.5. When the provider
  rejects the forced tool_choice, the request is sent again without it.
- With a config file that had settings but no model (after `fuseraft
  settings set` or the VS Code settings panel on a fresh install),
  `repl --vscode --model` refused to start. --model now completes it
  for the run, without saving it.
@fuseraft
fuseraft merged commit 337d50b into main Nov 13, 2026
7 checks passed
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