diff --git a/server/src/__tests__/agent-conversations.test.ts b/server/src/__tests__/agent-conversations.test.ts index ad975ffba98..fd5b774ffe9 100644 --- a/server/src/__tests__/agent-conversations.test.ts +++ b/server/src/__tests__/agent-conversations.test.ts @@ -1058,6 +1058,15 @@ describe("chat prompt policy", () => { expect(prompt).toContain("//agents//runs/"); }); + it("says the task-chat lab exists only under pnpm dev in the person's own checkout", () => { + expect(AGENT_CHAT_DIRECTIVE).toContain("Some developer labs, including the task-chat interaction lab at //dev/task-chat-lab, are registered only in a development build of the UI"); + expect(AGENT_CHAT_DIRECTIVE).not.toContain("Developer labs, such as"); + expect(AGENT_CHAT_DIRECTIVE).toContain("the design guide and the ux-lab pages, are registered in every build"); + expect(AGENT_CHAT_DIRECTIVE).toContain("running pnpm dev in their own Paperclip checkout and visiting //dev/task-chat-lab"); + const prompt = buildPaperclipTaskMarkdown({ issue: { id: "chat", identifier: null, title: "Chat", workMode: "ask", conversationAgentId: "agent" } }); + expect(prompt).toContain("//dev/task-chat-lab"); + }); + 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/__tests__/openapi-routes.test.ts b/server/src/__tests__/openapi-routes.test.ts index 758766bebe4..0b28e22572a 100644 --- a/server/src/__tests__/openapi-routes.test.ts +++ b/server/src/__tests__/openapi-routes.test.ts @@ -331,6 +331,16 @@ function loadSpecRoutes() { } describe("openapi routes", () => { + it("tells agents managed-agent profiles are created with the CLI, not a web page", () => { + const route = buildOpenApiSpec().paths["/api/companies/{companyId}/managed-agent-profiles"]; + for (const operation of [route.get, route.post]) { + expect(operation.description).toContain("Board only"); + expect(operation.description).toContain("There is no web page"); + } + expect(route.post.description).toContain("paperclipai managed-agent setup --company-id "); + expect(route.post.description).toContain("--acknowledge-retention"); + }); + it("documents the export include body so agents can request projects and skills", () => { const spec = buildOpenApiSpec(); for (const path of ["/api/companies/{companyId}/exports", "/api/companies/{companyId}/exports/preview"]) { diff --git a/server/src/routes/openapi.ts b/server/src/routes/openapi.ts index cb274455174..02dea5ce76a 100644 --- a/server/src/routes/openapi.ts +++ b/server/src/routes/openapi.ts @@ -7595,6 +7595,7 @@ registry.registerPath({ path: "/api/companies/{companyId}/managed-agent-profiles", tags: ["agents"], summary: "List Claude Managed Agent profiles for a company", + description: "Board only: agent credentials get 403. There is no web page for Claude Managed Agent profiles; see the POST route for how a board user creates one.", request: { params: z.object({ companyId: z.string() }) }, responses: { 200: r.ok(), 401: r.unauthorized, 403: r.forbidden }, }); @@ -7604,7 +7605,7 @@ registry.registerPath({ path: "/api/companies/{companyId}/managed-agent-profiles", tags: ["agents"], summary: "Create or operator-attest a Claude Managed Agent profile", - description: "Board only: agent credentials get 403. A Claude Managed Agent runs on Anthropic's managed-agents beta. A board operator creates the company profile with an Anthropic API-key secret and a limited environment (no hosts, no packages), attests its qualification and explicitly acknowledges stateful retention before it can be enabled.", + description: "Board only: agent credentials get 403. A Claude Managed Agent runs on Anthropic's managed-agents beta. A board operator creates the company profile with an Anthropic API-key secret and a limited environment (no hosts, no packages), attests its qualification and explicitly acknowledges stateful retention before it can be enabled. There is no web page for this: the board user runs the CLI command `paperclipai managed-agent setup --company-id --profile-key --display-name --api-key-secret-id --acknowledge-retention` with ANTHROPIC_API_KEY set in their shell (add --probe for a read-only qualification check first). It creates or adopts the limited Anthropic Agent and Environment, qualifies them and calls this route with board credentials. The secret itself is added on the company Secrets page, //company/settings/secrets.", request: { params: z.object({ companyId: z.string() }), body: jsonBody( diff --git a/server/src/services/agent-conversations.ts b/server/src/services/agent-conversations.ts index e54f7d98945..8fac4340e74 100644 --- a/server/src/services/agent-conversations.ts +++ b/server/src/services/agent-conversations.ts @@ -119,6 +119,8 @@ When a reply lists many tasks, write each task identifier in full, such as RUN-1 A person's own display name and avatar belong to their account, and only they can change them in their profile settings at //company/settings/instance/profile. Agent credentials cannot edit a person's profile, and renaming an agent, a member record or the company does not change it. When the person asks to change their own name or avatar, link that page instead of attempting the change. +Some developer labs, including the task-chat interaction lab at //dev/task-chat-lab, are registered only in a development build of the UI. A production or hosted instance has no task-chat lab page and no setting turns one on, so do not probe its bundle or try to open the lab with a browser. Tell the person the task-chat lab is development-only and that they can open it by running pnpm dev in their own Paperclip checkout and visiting //dev/task-chat-lab on that dev server. Other lab pages, such as the design guide and the ux-lab pages, are registered in every build, so open those normally. + Ready-made teams are installable packages in Paperclip's teams catalog, not agents already in this company. When the person asks whether a ready-made team exists, or refers to one, list the catalog with GET /api/teams/catalog and choose by its descriptions and roles, since teams are not named after every kind of project. When you recommend a team, name its roles (agentSlugs), every required skill (requiredSkills, by its ref) and every configuration input (envInputs), and say that a catalog listing does not mean the team's accounts are configured. The catalog is the only source of ready-made teams: do not look for others in package registries, repositories or the web. A team chosen earlier in this chat may be recorded in its task context (get_task_context). POST /api/companies/{companyId}/teams/catalog/{catalogId}/preview shows what an install would add and creates no resources. Installing needs a board user or an agent with permission to create agents. The web app has no teams catalog page, so do not link one: name the team and its id, and when you cannot install, tell the person that a board user can run paperclipai teams install --company-id . After an install, link the installed agents and projects at their own pages. This conversation and your credentials belong to one company. A task identifier whose prefix differs from this conversation's prefix belongs to another company or to none, and you cannot read it here, even when the person can open it themselves: a lookup that is not found does not mean the task does not exist. Do not search for it further, guess its content or copy anything from it. Say that this chat can only work in this company, and that to use that task the person can switch to its company and open a chat there. Link the task at //issues/, taking the prefix from the identifier the person gave; this is the one link that does not use this conversation's prefix.