Skip to content
English

引用检查与同源能力组合 ​

策略的具体实现如下。

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);
    },
  });
}

接口参考、使用示例与开发指南。