引用检查与同源能力组合
策略的具体实现如下。
ts
export function validateToolReferences(
names: Iterable<string>,
references: readonly CapabilityToolReferences[],
): void {
const available = new Set(names);
for (const reference of references) {
breakWhile(!reference.id?.trim(), 'Invalid tool reference owner');
const required = reference.requiredToolIds;
breakWhile(!Array.isArray(required), 'Tool references require requiredToolIds');
for (const name of [...required!, ...(reference.optionalToolIds ?? [])]) {
breakWhile(!available.has(name), `Unregistered tool reference: ${reference.id} -> ${name}`);
}
}
}
export function defineCapabilityCatalog<Module extends CapabilityModule>(
definitions: readonly Module[],
options: CapabilityCatalogOptions<Module> = {},
) {
const catalog = readonlyCatalog<Module>(
definitions,
(id) => new TypeError(`Unknown capability module: ${id}`),
);
const modules = catalog.definitions;
const owners = new Map<string, Readonly<Module>>();
const tools: Module['tools'][number][] = [];
for (const module of modules) {
breakWhile(!module.description?.trim(), 'Invalid capability module description');
for (const tool of module.tools as Module['tools']) {
const { id } = tool;
breakWhile(!id?.trim() || owners.has(id!), `Invalid or duplicate capability tool: ${id}`);
owners.set(id!, module);
tools.push(tool);
}
}
validateToolReferences(
owners.keys(),
modules.flatMap((module) =>
options.toolReferences
? synchronous(
options.toolReferences(module),
'Capability reference projections must be synchronous',
)
: [],
),
);
return Object.freeze({
...catalog,
tools: Object.freeze(tools),
findToolOwner(toolId: string): Readonly<Module> | undefined {
return owners.get(toolId);
},
});
}