feat(agents): resolve agent shortnames to UUIDs in route params
Add router.param middleware that normalizes agent references, allowing shortnames to be used in place of UUIDs in agent API routes. Includes company-scoped lookup with ambiguity detection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
createAgentKeySchema,
|
||||
createAgentHireSchema,
|
||||
createAgentSchema,
|
||||
isUuidLike,
|
||||
resetAgentSessionSchema,
|
||||
testAdapterEnvironmentSchema,
|
||||
updateAgentPermissionsSchema,
|
||||
@@ -26,7 +27,7 @@ import {
|
||||
logActivity,
|
||||
secretService,
|
||||
} from "../services/index.js";
|
||||
import { forbidden, unprocessable } from "../errors.js";
|
||||
import { conflict, forbidden, unprocessable } from "../errors.js";
|
||||
import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
|
||||
import { findServerAdapter, listAdapterModels } from "../adapters/index.js";
|
||||
import { redactEventPayload } from "../redaction.js";
|
||||
@@ -114,6 +115,38 @@ export function agentRoutes(db: Db) {
|
||||
throw forbidden("Only CEO or agent creators can modify other agents");
|
||||
}
|
||||
|
||||
async function resolveCompanyIdForAgentReference(req: Request): Promise<string | null> {
|
||||
const companyIdQuery = req.query.companyId;
|
||||
const requestedCompanyId =
|
||||
typeof companyIdQuery === "string" && companyIdQuery.trim().length > 0
|
||||
? companyIdQuery.trim()
|
||||
: null;
|
||||
if (requestedCompanyId) {
|
||||
assertCompanyAccess(req, requestedCompanyId);
|
||||
return requestedCompanyId;
|
||||
}
|
||||
if (req.actor.type === "agent" && req.actor.companyId) {
|
||||
return req.actor.companyId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function normalizeAgentReference(req: Request, rawId: string): Promise<string> {
|
||||
const raw = rawId.trim();
|
||||
if (isUuidLike(raw)) return raw;
|
||||
|
||||
const companyId = await resolveCompanyIdForAgentReference(req);
|
||||
if (!companyId) {
|
||||
throw unprocessable("Agent shortname lookup requires companyId query parameter");
|
||||
}
|
||||
|
||||
const resolved = await svc.resolveByReference(companyId, raw);
|
||||
if (resolved.ambiguous) {
|
||||
throw conflict("Agent shortname is ambiguous in this company. Use the agent ID.");
|
||||
}
|
||||
return resolved.agent?.id ?? raw;
|
||||
}
|
||||
|
||||
function parseSourceIssueIds(input: {
|
||||
sourceIssueId?: string | null;
|
||||
sourceIssueIds?: string[];
|
||||
@@ -259,6 +292,15 @@ export function agentRoutes(db: Db) {
|
||||
};
|
||||
}
|
||||
|
||||
router.param("id", async (req, _res, next, rawId) => {
|
||||
try {
|
||||
req.params.id = await normalizeAgentReference(req, String(rawId));
|
||||
next();
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/adapters/:type/models", async (req, res) => {
|
||||
const type = req.params.type as string;
|
||||
const models = await listAdapterModels(type);
|
||||
|
||||
Reference in New Issue
Block a user