mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 05:11:49 +01:00
fix(ui): let chat review requests open the document they ask about (#20590)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - In chat, an agent can end its turn on a confirmation card that asks
the person to review a saved document
> - The full task view links the card's document, but the compact chat
card showed the document key as plain text unless it was the plan
> - A person who is asked to review a draft in chat could not open the
draft from the card
> - This pull request links a document on the same chat to its
`#document-<key>` panel, the same link a reply uses
> - The benefit is that a review request in chat lets the person read
what they are asked to approve
## Linked Issues or Issue Description
**What happened?**
In a chat eval run on master `f4337bb5fb`
(`questions-and-approvals.reject-and-revise`), the agent saved a `draft`
document and ended its turn on a confirmation card "Review research
notes introduction draft" with `target: { type: "issue_document", key:
"draft", revisionId }`. In the chat composer takeover, the card showed
`draft` as a plain chip with no link.
**Expected behavior**
A confirmation card in chat opens the document it asks the person to
review, like the full card in the task view does.
**Steps to reproduce**
Create a pending `request_confirmation` on a chat task with
`payload.target = { type: "issue_document", key: "draft", revisionId }`.
Open the chat. The takeover shows the `draft` chip without a link.
## What Changed
- `CompactTarget` in `TaskChatCompactInteractionCard.tsx` gives an
`issue_document` target on the same chat the href `#document-<key>`.
Plan targets, targets with an explicit `href`, attachments and documents
on other tasks keep their current behavior.
- Added a `TaskChatThread` test: a pending draft review request in the
takeover links `#document-draft`.
## Verification
- `npx vitest run src/components/TaskChatThread.test.tsx -t "links a
review request"` in `ui`: red before the fix, green after.
- `npx vitest run src/components/TaskChatThread.test.tsx
src/components/coordinator/CoordinatorTaskCommitment.test.tsx
src/lib/issue-thread-interactions.test.ts`: 457 passed.
- `node scripts/check-token-gates.mjs`: all gates clean.
- Paid chat eval on a temporary branch with this change: see the comment
on this PR.
## Risks
- Low risk. Plan review cards are unchanged; their plan preview already
opens the plan.
- No API, schema or stored state changes.
## Model Used
- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), agentic coding with
tool use 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>
This commit is contained in:
1 parent
9816d2d25c
commit
ed3ffc3bc7
2 files changed
+15
-1
No files matched your search
@@ -4218,6 +4218,14 @@ describe.each([true, false])("Unanswered question history (conversationMode=%s)"
|
||||
expect(pendingIndicator()).toBeNull();
|
||||
});
|
||||
|
||||
it("links a review request's own document so the person can open what it asks them to review", () => {
|
||||
const review = { ...planReviewInteraction(), id: "draft-review", title: "Review draft", payload: { version: 1, prompt: "Review the unpublished draft.",
|
||||
target: { type: "issue_document", key: "draft", revisionId: "draft-revision-1" } } } as IssueThreadInteraction;
|
||||
render(<TaskChatThread {...props} comments={[]} interactions={[review]} />);
|
||||
const link = takeover()?.querySelector<HTMLAnchorElement>('a[href="#document-draft"]');
|
||||
expect(link?.textContent).toContain("draft");
|
||||
});
|
||||
|
||||
it("keeps unrelated approvals and accepted plan history when a plan changes", () => {
|
||||
planState.data = planDocument({ latestRevisionId: "revision-4", latestRevisionNumber: 4, updatedAt: new Date("2026-08-23T10:03:00Z") });
|
||||
const review = { ...planReviewInteraction(), payload: { version: 1, prompt: "Review another task", target: { type: "issue_document", issueId: "other-task", key: "plan", revisionId: "revision-3" } } } as IssueThreadInteraction;
|
||||
|
||||
@@ -306,7 +306,13 @@ function CompactTarget({
|
||||
if (!target || !label) return null;
|
||||
const href = target.type === "issue_attachment"
|
||||
? `/api/attachments/${encodeURIComponent(target.attachmentId)}/content`
|
||||
: target.href ? normalizeRequestConfirmationTargetHref(target.href) : null;
|
||||
: target.href ? normalizeRequestConfirmationTargetHref(target.href)
|
||||
// A document on this chat opens in its document panel, like a reply's
|
||||
// `#document-<key>` link, so the person can read what they are asked to review.
|
||||
// Plan reviews keep their header chip; their plan preview opens the plan.
|
||||
: target.type === "issue_document" && target.key !== "plan" && (target.issueId ?? interaction.issueId) === interaction.issueId
|
||||
? `#document-${encodeURIComponent(target.key)}`
|
||||
: null;
|
||||
if (href) {
|
||||
return (
|
||||
<a
|
||||
|
||||
Reference in new issue
Block a user