fix(plugins): treat refreshable catalogs as requiring runtime discovery (#93786)

Treat refreshable manifest catalog rows as non-authoritative and load the owning plugin for runtime/cache-backed discovery. Adds focused regression coverage for entries-only and full discovery paths.
This commit is contained in:
liuhao1024
2026-06-17 08:38:34 +08:00
committed by GitHub
parent 5c74fde912
commit d2279591bf
2 changed files with 36 additions and 4 deletions

View File

@@ -67,7 +67,7 @@ function createManifestPlugin(id: string): PluginManifestRecord {
function createManifestPluginWithModelCatalog(
id: string,
discovery: "static" | "runtime" = "static",
discovery: "static" | "refreshable" | "runtime" = "static",
): PluginManifestRecord {
return {
...createManifestPluginWithoutDiscovery({ id }),
@@ -263,6 +263,38 @@ describe("resolvePluginDiscoveryProvidersRuntime", () => {
expect(mocks.resolvePluginProviders).not.toHaveBeenCalled();
});
it("does not synthesize manifest entry providers for refreshable catalogs", () => {
mocks.resolveDiscoveredProviderPluginIds.mockReturnValue(["token-plan"]);
mocks.loadPluginMetadataSnapshot.mockReturnValue({
index: { plugins: [] },
manifestRegistry: {
plugins: [createManifestPluginWithModelCatalog("token-plan", "refreshable")],
diagnostics: [],
},
});
expect(resolvePluginDiscoveryProvidersRuntime({ discoveryEntriesOnly: true })).toStrictEqual(
[],
);
expect(mocks.resolvePluginProviders).not.toHaveBeenCalled();
});
it("loads the full plugin for refreshable manifest catalog rows", () => {
const refreshableProvider = createProvider({ id: "token-plan", mode: "catalog" });
mocks.resolveDiscoveredProviderPluginIds.mockReturnValue(["token-plan"]);
mocks.resolvePluginProviders.mockReturnValue([refreshableProvider]);
mocks.loadPluginMetadataSnapshot.mockReturnValue({
index: { plugins: [] },
manifestRegistry: {
plugins: [createManifestPluginWithModelCatalog("token-plan", "refreshable")],
diagnostics: [],
},
});
expect(resolvePluginDiscoveryProvidersRuntime({})).toStrictEqual([refreshableProvider]);
expect(requireResolvePluginProvidersParams().onlyPluginIds).toEqual(["token-plan"]);
});
it("loads the full plugin when one manifest catalog provider is runtime-owned", () => {
const runtimeProvider = createProvider({ id: "xiaomi-token-plan", mode: "catalog" });
mocks.resolveDiscoveredProviderPluginIds.mockReturnValue(["xiaomi"]);

View File

@@ -217,7 +217,7 @@ function resolveManifestModelCatalogProviders(
}
const plan = planManifestModelCatalogRows({ registry: { plugins: [plugin] } });
for (const entry of plan.entries) {
if (entry.rows.length === 0 || entry.discovery === "runtime") {
if (entry.rows.length === 0 || entry.discovery === "runtime" || entry.discovery === "refreshable") {
continue;
}
const providerConfig = providerConfigFromManifestRows(entry.rows);
@@ -249,7 +249,7 @@ function resolveRuntimeManifestCatalogPluginIds(
);
const ownsRuntimeDiscovery = Object.entries(plugin.modelCatalog?.discovery ?? {}).some(
([provider, discovery]) =>
discovery === "runtime" && ownedProviders.has(normalizeProviderId(provider)),
(discovery === "runtime" || discovery === "refreshable") && ownedProviders.has(normalizeProviderId(provider)),
);
if (ownsRuntimeDiscovery) {
pluginIds.add(plugin.id);
@@ -259,7 +259,7 @@ function resolveRuntimeManifestCatalogPluginIds(
continue;
}
const plan = planManifestModelCatalogRows({ registry: { plugins: [plugin] } });
if (plan.entries.some((entry) => entry.discovery === "runtime")) {
if (plan.entries.some((entry) => entry.discovery === "runtime" || entry.discovery === "refreshable")) {
pluginIds.add(plugin.id);
}
}