2026-09-24 15:48:45 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 能力目录(架构设计 2 / 4:registry 模块)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 保存已注册 Provider 与它们声明的能力;上层按身份取「能力清单」(A4 起按策略过滤,
|
|
|
|
|
|
* 当前只做注册与查找)。能力目录是唯一来源——引擎的工具列表是它的投影。
|
|
|
|
|
|
*/
|
|
|
|
|
|
import type { Capability, Provider, ProviderManifest } from '@aps/provider-sdk';
|
|
|
|
|
|
|
|
|
|
|
|
export interface RegisteredProvider {
|
|
|
|
|
|
manifest: ProviderManifest;
|
|
|
|
|
|
provider: Provider;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ResolvedCapability {
|
|
|
|
|
|
capability: Capability;
|
|
|
|
|
|
provider: Provider;
|
|
|
|
|
|
providerId: string;
|
2026-09-29 10:59:34 +08:00
|
|
|
|
/** 该系统是否需要平台用户绑定账号(A4.1);缺省 true */
|
|
|
|
|
|
requiresIdentity: boolean;
|
2026-09-24 15:48:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export class CapabilityRegistry {
|
|
|
|
|
|
private readonly providers = new Map<string, RegisteredProvider>();
|
|
|
|
|
|
|
|
|
|
|
|
async register(provider: Provider): Promise<ProviderManifest> {
|
|
|
|
|
|
const manifest = await provider.describe();
|
|
|
|
|
|
if (manifest.platformVersion !== 1) {
|
|
|
|
|
|
throw new Error(`Provider ${manifest.id} 声明兼容平台版本 ${manifest.platformVersion},当前平台只支持 1`);
|
|
|
|
|
|
}
|
|
|
|
|
|
this.providers.set(manifest.id, { manifest, provider });
|
|
|
|
|
|
return manifest;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
list(): Capability[] {
|
|
|
|
|
|
return [...this.providers.values()].flatMap((entry) => entry.manifest.capabilities);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
resolve(capabilityId: string): ResolvedCapability | undefined {
|
|
|
|
|
|
for (const entry of this.providers.values()) {
|
|
|
|
|
|
const capability = entry.manifest.capabilities.find((item) => item.id === capabilityId);
|
2026-09-29 10:59:34 +08:00
|
|
|
|
if (capability) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
capability,
|
|
|
|
|
|
provider: entry.provider,
|
|
|
|
|
|
providerId: entry.manifest.id,
|
|
|
|
|
|
requiresIdentity: entry.manifest.requiresIdentity !== false,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2026-09-24 15:48:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
return undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
providerIds(): string[] {
|
|
|
|
|
|
return [...this.providers.keys()];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async health(): Promise<Array<{ providerId: string; status: string; detail?: string }>> {
|
|
|
|
|
|
const results: Array<{ providerId: string; status: string; detail?: string }> = [];
|
|
|
|
|
|
for (const [providerId, entry] of this.providers) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const health = await entry.provider.health();
|
|
|
|
|
|
results.push(health.detail === undefined ? { providerId, status: health.status } : { providerId, status: health.status, detail: health.detail });
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
results.push({ providerId, status: 'down', detail: error instanceof Error ? error.message : '健康探测失败' });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return results;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|