From 2fb4837cca929954d026d4663e367a669b8ad591 Mon Sep 17 00:00:00 2001 From: Dotta <34892728+cryppadotta@users.noreply.github.com> Date: Sat, 7 Nov 2026 18:41:35 -0600 Subject: [PATCH] fix(chat): tell chat how to link execution runs and name their agents (#19889) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Chat lets a person ask an agent about work, such as the runs behind a task > - The chat guidance gives a link template for tasks only. It does not give one for execution runs > - The issue runs API returns `agentId` and the run `id`, but no agent name and no link > - So when a person asks "Show me the runs behind this website task", the agent lists raw UUIDs. It does not link each run. It does not name the agent that did the work > - This pull request adds the registered run route to the chat link guidance. It also tells chat to read the agent and name it, not show a raw ID > - The benefit is that a person can open each run (including the cancelled attempt) and sees who ran it ## Linked Issues or Issue Description **What happened?** A chat agent was asked to show the runs behind a task that had a cancelled attempt and a successful retry. It read `GET /api/issues/{id}/runs` correctly, but its reply showed both runs as raw UUIDs in code spans and named the agent as "`fe03dd15…`, the Website Brief worker" instead of its name. It gave no run links. **What did you expect?** Each run links to its run detail page (`//agents//runs/`), and the reply names the agent that executed it. **Steps to reproduce** 1. Create a task assigned to an agent, cancel its first run, and retry it so a second run succeeds. 2. In chat, ask "Show me the runs behind this website task." 3. The reply lists run UUIDs without links and identifies the agent by ID. Refs #19614 (the chat catalog eval case `activity.find-runs` shows this failure). ## What Changed - `server/src/services/agent-conversations.ts`: the chat link guidance now gives the run route `//agents//runs/` and tells chat to read and name the agent instead of showing a raw ID. - `server/src/__tests__/agent-conversations.test.ts`: a regression test checks that the run template matches the registered UI route and reaches the chat task prompt. ## Verification - `cd server && npx vitest run src/__tests__/agent-conversations.test.ts -t "chat prompt policy"`: 7 passed. The new test fails without the guidance change. - `src/services/heartbeat/task-markdown.test.ts` passes. - The embedded-Postgres suite in `agent-conversations.test.ts` did not start in my local sandbox (Postgres init error). It does not depend on this prompt text. CI runs it. - End-to-end: the chat catalog case `activity.find-runs` is rerun with this commit on its eval branch. ## Risks - Low risk. This is prompt guidance text only. No API, schema, or UI change. - It conflicts textually with #17985, which edits the same guidance line. The merge is simple: keep both sentences. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`), used through Claude Code with tool use (shell, file edits). Default reasoning mode. ## 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 --- .../src/__tests__/agent-conversations.test.ts | 18 ++++++++++++++++++ server/src/services/agent-conversations.ts | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/server/src/__tests__/agent-conversations.test.ts b/server/src/__tests__/agent-conversations.test.ts index 70fbf794854..2a4ceafb6dc 100644 --- a/server/src/__tests__/agent-conversations.test.ts +++ b/server/src/__tests__/agent-conversations.test.ts @@ -1,3 +1,4 @@ +import { readFileSync } from "node:fs"; import { createLocalAgentJwt } from "../agent-auth-jwt.js"; import { applyRunnerGoalPrpEvent } from "../services/runner-goals.js"; import { mkdtemp, rm } from "node:fs/promises"; @@ -1002,6 +1003,23 @@ describe("chat prompt policy", () => { expect(AGENT_CHAT_DIRECTIVE).toContain("In Ask mode, discuss the plan without creating or revising documents or approval cards"); }); + it("tells chat how to link execution runs to the registered run route and name their agents", () => { + const app = readFileSync(new URL("../../../ui/src/App.tsx", import.meta.url), "utf8"); + expect(app).toMatch(//agents//runs/ using the run's returned agentId."); + // Issue run listings expose the run ID as runId, not id; the guidance must name the field each response returns. + const activity = readFileSync(new URL("../services/activity.ts", import.meta.url), "utf8"); + const listing = activity.match(/runsForIssue:\s*async\b[\s\S]*?\.select\(\{([\s\S]*?)\n\s*\}\)/)?.[1] ?? ""; + expect(listing).toMatch(/^\s*runId:\s*heartbeatRuns\.id\s*,/m); + expect(listing).not.toMatch(/^\s*id:/m); + expect(AGENT_CHAT_DIRECTIVE).toContain("Issue run listings (GET /api/issues/{id}/runs) return the run ID as runId"); + expect(AGENT_CHAT_DIRECTIVE).toContain("use id only from responses that return the run itself, such as GET /api/heartbeat-runs/{runId}"); + expect(AGENT_CHAT_DIRECTIVE).not.toContain("returned agentId and id"); + expect(AGENT_CHAT_DIRECTIVE).toContain("read the agent and name it rather than showing a raw ID"); + const prompt = buildPaperclipTaskMarkdown({ issue: { id: "chat", identifier: null, title: "Chat", workMode: "ask", conversationAgentId: "agent" } }); + expect(prompt).toContain("//agents//runs/"); + }); + it("gives chat replies a usable route for both task and approval sources", () => { expect(AGENT_CHAT_DIRECTIVE).toContain("//issues/"); expect(AGENT_CHAT_DIRECTIVE).toContain("For approval links, use //approvals/"); diff --git a/server/src/services/agent-conversations.ts b/server/src/services/agent-conversations.ts index c4db78dde24..84592ac13f4 100644 --- a/server/src/services/agent-conversations.ts +++ b/server/src/services/agent-conversations.ts @@ -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 //issues/, deriving the prefix from the returned task identifier. For approval links, use //approvals/ 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 task links, use the company-prefixed relative path //issues/, deriving the prefix from the returned task identifier. For approval links, use //approvals/ 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 an execution run, link //agents//runs/ using the run's returned agentId. Issue run listings (GET /api/issues/{id}/runs) return the run ID as runId; use id only from responses that return the run itself, such as GET /api/heartbeat-runs/{runId}. Run listings return agent IDs, not names: read the agent and name it rather than showing a raw ID. When a reply concerns a specific agent, such as one you paused, resumed, configured, or reported on, link its profile at //agents/ using the agent's returned urlKey or id. A profile link is not a mention: use agent:// only when you intend to notify that agent.