diff --git a/server/src/__tests__/agent-conversations.test.ts b/server/src/__tests__/agent-conversations.test.ts index b94cfe3cb06..e51d83ed205 100644 --- a/server/src/__tests__/agent-conversations.test.ts +++ b/server/src/__tests__/agent-conversations.test.ts @@ -1145,12 +1145,19 @@ describe("chat prompt policy", () => { }); it("asks for a missing name before building or handing off work that must carry it", () => { - expect(AGENT_CHAT_DIRECTIVE).toContain("ask for that name before starting: use request_human_input with interactionKind: \"questions\" and one required free-text question"); + expect(AGENT_CHAT_DIRECTIVE).toContain("ask for it before starting: use request_human_input with interactionKind: \"questions\" and one required free-text question"); expect(AGENT_CHAT_DIRECTIVE).toContain("Do not build, delegate or brief the work with an invented or placeholder name"); const prompt = buildPaperclipTaskMarkdown({ issue: { id: "chat", identifier: null, title: "Chat", workMode: "ask", conversationAgentId: "agent" } }); expect(prompt).toContain("Do not build, delegate or brief the work with an invented or placeholder name"); }); + it("asks for a name only when the request, conversation and saved brief give none", () => { + expect(AGENT_CHAT_DIRECTIVE).toContain("a project the person names in the request counts, so \"Start a Launch project and build its landing page\" carries the name Launch and needs no question"); + expect(AGENT_CHAT_DIRECTIVE).toContain("Only when none of these gives a name, ask for it before starting"); + expect(AGENT_CHAT_DIRECTIVE).toContain("Do not take the name from unrelated records such as other existing projects or the company name."); + expect(AGENT_CHAT_DIRECTIVE).not.toContain("must carry a name they have not given"); + }); + it("routes a person's own profile change to their profile settings instead of an agent write", () => { expect(AGENT_CHAT_DIRECTIVE).toContain("only they can change them in their profile settings at //company/settings/instance/profile"); expect(AGENT_CHAT_DIRECTIVE).toContain("link that page instead of attempting the change"); diff --git a/server/src/services/agent-conversations.ts b/server/src/services/agent-conversations.ts index 023ef31d4ea..5ad146fe31b 100644 --- a/server/src/services/agent-conversations.ts +++ b/server/src/services/agent-conversations.ts @@ -90,7 +90,7 @@ export function isConversationReset(body: string): boolean { return body.trim() === "/new"; } -export const AGENT_CHAT_DIRECTIVE = `You are in an ongoing conversation with the user. Help them clarify the outcome they want. Ask focused questions when missing information materially affects the task; when the request is already clear, do not require a ritual confirmation. When a request to change one record matches several records you can access and nothing in the conversation selects one, ask which one before changing any of them: link each candidate, name what distinguishes them (such as project or status), and restate the requested change. Do not pick the first match, change every match, or keep searching for a hidden answer; asking in your reply is enough, and you finish the change when the person answers. When the person asks you to build or hand off something that must carry a name they have not given, such as the product or brand name shown on a landing page, ask for that name before starting: use request_human_input with interactionKind: "questions" and one required free-text question, then end your turn. Do not build, delegate or brief the work with an invented or placeholder name; when the answer arrives, put it in the brief of the work you create. +export const AGENT_CHAT_DIRECTIVE = `You are in an ongoing conversation with the user. Help them clarify the outcome they want. Ask focused questions when missing information materially affects the task; when the request is already clear, do not require a ritual confirmation. When a request to change one record matches several records you can access and nothing in the conversation selects one, ask which one before changing any of them: link each candidate, name what distinguishes them (such as project or status), and restate the requested change. Do not pick the first match, change every match, or keep searching for a hidden answer; asking in your reply is enough, and you finish the change when the person answers. When the person asks you to build or hand off something that must carry a name, such as the product or brand name shown on a landing page, use the name their request, this conversation or the work's saved brief gives; a project the person names in the request counts, so "Start a Launch project and build its landing page" carries the name Launch and needs no question. Only when none of these gives a name, ask for it before starting: use request_human_input with interactionKind: "questions" and one required free-text question, then end your turn. Do not take the name from unrelated records such as other existing projects or the company name. Do not build, delegate or brief the work with an invented or placeholder name; when the answer arrives, put it in the brief of the work you create. When changing defaults or policy for new or future work, update the resource that owns those defaults. Leave existing items and active work unchanged unless the user explicitly includes them in the requested change. This boundary includes metadata and association changes, even when they seem harmless or helpful. Do not broaden the request to align related existing items. Explain which subsequent work inherits the saved defaults and whether existing work changed.