Files
PaperClipAI/packages
DottaandClaude Opus 5.5 f7d41ca5bf fix(opencode): save an answer once when the model restates it after the completion call (#21025)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents that use OpenCode models reply in chat through the Runner's
OpenCode driver. The driver settles one final response, and Paperclip
saves it as the reply comment
> - #20999 made the driver keep the prose written before the
`paperclip_finish` call together with the message written after it. That
stopped the loss of an answer when the later message only said "Answered
above"
> - In chat-eval cohort 4 (OpenCode with DeepSeek v4.1 flash), the model
often wrote its whole answer, called `paperclip_finish`, and then wrote
the same answer again in other words. The driver saved both. 13 cases
had one saved reply that held the answer twice
> - This pull request saves only the later message when it restates the
earlier prose. A short pointer line still keeps the earlier answer
> - The benefit is that people, deliveries and the next turn read the
answer once, and #20999's protection stays in place

## Linked Issues or Issue Description

Refs #20999

**What happened?**
An OpenCode chat turn wrote its answer, called `paperclip_finish`, and
then wrote the same answer again with small wording changes. The saved
reply comment held both copies, one after the other. Example
(budgets-costs.set-budget): "I can't set this from chat — changing an
agent's monthly budget is a board-only action ..." followed by "I can't
change agent budgets from chat — that's board-only ...", both with the
same two budget links.

**Expected behavior**
The saved reply holds the answer once. When the later message only
refers back to the earlier answer, the saved reply still keeps the
earlier answer.

**Steps to reproduce**
1. Use an OpenCode agent with
`openrouter/deepseek/deepseek-v4.1-flash-1017`.
2. Ask a question that the model answers before `paperclip_finish` and
again after it.
3. Read the saved reply with `GET /api/issues/{id}/comments`. It holds
the answer twice.

**Paperclip version or commit**
master at f1aef0cb58.

## What Changed

- New `restatesEarlierReply(earlier, later)` in
`packages/paperclip-runner/src/drivers/opencode/restated-reply.ts`. The
later message restates the earlier prose only when all of these are
true: it keeps every link target and fenced code block of the earlier
prose, it is at least half as long, and it repeats at least half of the
earlier prose's distinct words. Identical text is always a restatement.
- `OpenCodeServerDriver` uses it in the path that #20999 added. When the
post-completion message restates the pre-completion prose, the driver
saves the post-completion message alone. Otherwise it joins both, as
before.
- The fake OpenCode server gets an
`answer-before-finish-then-restatement` turn that uses the recorded
cohort-4 texts.
- Tests: one driver test for the recorded shape, and unit tests for the
helper (identical, reworded, pointer line, dropped link, dropped code
block, different content).

## Verification

- `cd packages/paperclip-runner && npx vitest run
src/drivers/opencode/restated-reply.test.ts
src/drivers/opencode/opencode-server-driver.test.ts`: 87 tests pass.
This includes the #20999 tests ("Answered above" keeps the earlier
answer; long commentary before a short post-tool answer keeps both).
- Red/green: with the driver file from `origin/master`, the new driver
test fails (the saved text holds both copies). With the change, it
passes.
- `npx tsc -p packages/paperclip-runner/tsconfig.json --noEmit` passes.
- I ran the helper over all 18 recorded cohort-4 turns that had prose
both before and after `paperclip_finish`. It classified the 13 reported
duplicate replies (and 4 turns whose earlier line was a short status
that the later answer covers) as restatements. It kept both texts for
`access.cli-authorization`, where the later message is "Commands above
are ready to paste."
- A paid chat-eval run on a branch with this change is linked in a
comment below.

## Risks

- The check reads text, so it can be wrong at the margin. If it wrongly
calls an earlier answer a restatement, the saved reply loses that
earlier text. The link, code-block and length conditions keep the
references and the content of a substantial earlier answer; the earlier
prose remains in the run transcript.
- No saved run state, session state or event shape changes. A run saved
by the previous release resumes without change; only the text of a newly
settled final response differs.
- During a live run, the chat can still show the earlier prose as
progress above the saved answer, as it did before #20999.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, with tool use and code
execution in Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 23:54:27 -06:00
..