fix(chat): give chat replies the approval route (#19892)

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent Chat lets a person ask their agent about company state, such
as "What decisions are waiting on me?"
> - The chat directive tells the agent how to link a task:
`/<prefix>/issues/<identifier>`
> - The directive gives no route for an approval, and the approval tools
return no href
> - The completion feedback tells the agent not to guess routes, so the
agent names a pending approval but cannot link it
> - The person then cannot open the approval from the chat to decide it
> - This pull request adds the approval route that the board UI already
serves to the chat directive
> - The benefit is that a chat reply can link each pending approval to
its exact source

## Linked Issues or Issue Description

**What happened?**
In the Agent Chat eval `inbox-search.show-decisions`, the person asked
"What decisions are waiting on me?". The agent found the pending hire
approval and listed it. It did not link it. Its recorded reasoning said
that it had no known href for approvals and that it must not invent
URLs. Task sources in the same reply had working links.

**Expected behavior**
The reply links the pending approval, so the person can open it and
decide it.

**Steps to reproduce**
1. Create a pending `hire_agent` approval in a company.
2. In Agent Chat, ask "What decisions are waiting on me?".
3. See that the reply names the approval but gives no link to it.

**Paperclip version or commit**
`master` at the base of this branch.

**Agent adapter(s) involved**
Not adapter-specific (core bug). The chat directive is shared by all
runners.

## What Changed

- `AGENT_CHAT_DIRECTIVE` now says to link approvals as
`/<prefix>/approvals/<approvalId>`, with the same company prefix as task
links. The board UI serves this route (`approvals/:approvalId` in
`ui/src/App.tsx`).
- Added a regression test that the directive gives routes for both tasks
and approvals and keeps the "never invent a hostname" rule.

## Verification

- `pnpm exec vitest run
server/src/__tests__/agent-conversations.test.ts` passes (41 tests). The
new test fails without the directive change.
- End to end: the change is cherry-picked onto the eval branch
`chat-eval/case-show-decisions` and run in the Runner Full-Stack E2E
workflow for
`chat-features.runner-opencode.local.inbox-search.show-decisions`.

## Risks

- Low risk. The change adds one sentence to the chat prompt. It does not
change routes, permissions or tool results.
- The prompt becomes slightly longer for every chat turn.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), used through Claude
Code with tool use (shell, file edits, GitHub CLI).

## 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
- [ ] 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:
DottaandClaude Opus 5.5 authored and GitHub committed 2026-11-07 16:27:47 -06:00
1 parent cbf811cd3b
commit 29b6411660
2 files changed
+7 -1

No files matched your search

@@ -995,6 +995,12 @@ describe("chat prompt policy", () => {
expect(AGENT_CHAT_DIRECTIVE).toContain("In Ask mode, discuss the plan without creating or revising documents or approval cards");
});
it("gives chat replies a usable route for both task and approval sources", () => {
expect(AGENT_CHAT_DIRECTIVE).toContain("/<prefix>/issues/<identifier>");
expect(AGENT_CHAT_DIRECTIVE).toContain("For approval links, use /<prefix>/approvals/<approvalId>");
expect(AGENT_CHAT_DIRECTIVE).toContain("Never invent a hostname for a Paperclip link.");
});
it.each([true, false])("preserves rejected-plan changes in task markdown (includeDescription=%s)", (includeDescription) => {
const prompt = buildPaperclipTaskMarkdown({
issue: { id: "chat", identifier: null, title: "Chat", workMode: "planning", conversationAgentId: "agent" },
+1 -1
View File
@@ -110,7 +110,7 @@ Create ordinary assigned tasks; this conversation is never a parent. Choose the
For review or follow-up tasks, include the existing source materials the assignee needs, not just task identifiers or a rubric. Read the source task's saved documents and comments, then copy the relevant existing content into the handoff or attach resources the recipient can actually read. A new task's tools may only expose its own documents and history. Supplying existing source material is coordination, not creating the assigned deliverable.
For task links, use the company-prefixed relative path /<prefix>/issues/<identifier>, deriving the prefix from the returned task identifier. An absolute URL is appropriate only when its actual origin was supplied by the platform. Never invent a hostname for a Paperclip link.
For task links, use the company-prefixed relative path /<prefix>/issues/<identifier>, deriving the prefix from the returned task identifier. For approval links, use /<prefix>/approvals/<approvalId> with the same company prefix and the returned approval id, so the person can open the approval to decide it. An absolute URL is appropriate only when its actual origin was supplied by the platform. Never invent a hostname for a Paperclip link.
For status updates, distinguish recorded task status from active execution and verified progress. Read the latest relevant comments and run outcome before explaining a blocker or claiming work is underway. Use the advertised API tools for another task's details when needed. A completed dependency does not prove a block is stale; report the assignee's recorded reason. Agent configuration may be redacted: an empty configuration object without configuration-read permission does not prove settings are disabled or at their defaults. If the evidence is unavailable, say what you could verify and what remains unknown rather than guessing or recommending a status change.