diff --git a/doc/DEVELOPING.md b/doc/DEVELOPING.md index 08986d2ef43..26ad54fa183 100644 --- a/doc/DEVELOPING.md +++ b/doc/DEVELOPING.md @@ -715,6 +715,11 @@ a real mention. **Done** finishes setup once webhook verification and required account linking are complete, whether or not a test message was sent. The separate strict connection-test API retains its conversation and delivery checks. +New Slack conversations receive default communication guidance that requires a +clickable link to each task the agent creates. Agents use the public task URL +from Paperclip tools or task context and report when a link is unavailable. +Existing conversations keep their original communication guidance snapshot. + ### Chat activity pagination and callback diagnostics The connection Activity tab loads 25 records per page. `GET /api/chat-endpoints/:id/activity?limit=25` diff --git a/server/src/services/chat-communication-guidance.test.ts b/server/src/services/chat-communication-guidance.test.ts index a1f77369766..cca070de8f3 100644 --- a/server/src/services/chat-communication-guidance.test.ts +++ b/server/src/services/chat-communication-guidance.test.ts @@ -22,6 +22,15 @@ describe("initial medium communication guidance", () => { expect(buildChatCommunicationGuidance({ provider: "slack", isDirectMessage: true })).toContain("direct conversation"); }); + it.each([false, true])("requires public links for created Slack tasks (DM: %s)", (isDirectMessage) => { + const guidance = buildChatCommunicationGuidance({ provider: "slack", isDirectMessage }); + expect(guidance).toContain("include a clickable link to each created task"); + expect(guidance).toContain("task identifier or title as the link text"); + expect(guidance).toContain("public task URL returned by Paperclip tools or supplied in task context"); + expect(guidance).toContain("never guess a URL"); + expect(guidance).toContain("If no public task URL is available, say that the link is unavailable"); + }); + it.each(CHAT_PROVIDERS.filter((provider) => provider !== "slack"))("leaves %s unchanged", (provider) => { expect(buildChatCommunicationGuidance({ provider, isDirectMessage: false, communicationInstructions: "Ignored" })).toBeNull(); }); diff --git a/server/src/services/chat-communication-guidance.ts b/server/src/services/chat-communication-guidance.ts index c76fcf95002..d2f3344939e 100644 --- a/server/src/services/chat-communication-guidance.ts +++ b/server/src/services/chat-communication-guidance.ts @@ -9,6 +9,7 @@ const providerGuidance: Partial> = { ...slackTaskUpdateGuidance, "Lead with the answer or outcome. Use compact paragraphs or short lists, and omit routine execution bookkeeping. Honor requests for more detail or exact output over default brevity.", "Put small answers directly in the message. For substantial plans, reports, and other deliverables, use your normal document or artifact tools, then share a useful summary and accessible links or supported attachments in Slack. Follow the runtime's file-delivery contract and do not claim delivery until confirmed.", + "When you create tasks, include a clickable link to each created task in your reply. Use the task identifier or title as the link text, not a bare task ID. Use the public task URL returned by Paperclip tools or supplied in task context; never guess a URL or use a localhost, API, or sandbox address. If no public task URL is available, say that the link is unavailable.", "Ask useful questions through the existing human-input tools. Continue normal Paperclip planning, task creation, assignment, delegation, and approval workflows; these communication instructions grant no additional authority.", ].join("\n\n"), };