feat: enforce agent icon enum and expose via LLM endpoint

Move icon name list to shared constants with strict enum validation.
Add /llms/agent-icons.txt endpoint, pass icon through hire flow,
and update skills to reference icon discovery step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Forgotten
2026-02-25 08:39:11 -06:00
parent 9f049aa4f3
commit 1c2873d22a
10 changed files with 113 additions and 11 deletions

View File

@@ -512,6 +512,7 @@ export function agentRoutes(db: Db) {
name: normalizedHireInput.name,
role: normalizedHireInput.role,
title: normalizedHireInput.title ?? null,
icon: normalizedHireInput.icon ?? null,
reportsTo: normalizedHireInput.reportsTo ?? null,
capabilities: normalizedHireInput.capabilities ?? null,
adapterType: requestedAdapterType,

View File

@@ -1,5 +1,6 @@
import { Router, type Request } from "express";
import type { Db } from "@paperclip/db";
import { AGENT_ICON_NAMES } from "@paperclip/shared";
import { forbidden } from "../errors.js";
import { listServerAdapters } from "../adapters/index.js";
import { agentService } from "../services/agents.js";
@@ -38,6 +39,9 @@ export function llmRoutes(db: Db) {
"- GET /api/agents/:id/configuration",
"- POST /api/companies/:companyId/agent-hires",
"",
"Agent identity references:",
"- GET /llms/agent-icons.txt",
"",
"Notes:",
"- Sensitive values are redacted in configuration read APIs.",
"- New hires may be created in pending_approval state depending on company settings.",
@@ -46,6 +50,21 @@ export function llmRoutes(db: Db) {
res.type("text/plain").send(lines.join("\n"));
});
router.get("/llms/agent-icons.txt", async (req, res) => {
await assertCanRead(req);
const lines = [
"# Paperclip Agent Icon Names",
"",
"Set the `icon` field on hire/create payloads to one of:",
...AGENT_ICON_NAMES.map((name) => `- ${name}`),
"",
"Example:",
'{ "name": "SearchOps", "role": "researcher", "icon": "search" }',
"",
];
res.type("text/plain").send(lines.join("\n"));
});
router.get("/llms/agent-configuration/:adapterType.txt", async (req, res) => {
await assertCanRead(req);
const adapterType = req.params.adapterType as string;