mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:30:44 +00:00
fix: report model catalog manifest conflicts
This commit is contained in:
@@ -10,6 +10,7 @@ export {
|
||||
} from "./normalize.js";
|
||||
export { planManifestModelCatalogRows } from "./manifest-planner.js";
|
||||
export type {
|
||||
ManifestModelCatalogConflict,
|
||||
ManifestModelCatalogPlan,
|
||||
ManifestModelCatalogPlanEntry,
|
||||
ManifestModelCatalogPlugin,
|
||||
|
||||
@@ -51,6 +51,7 @@ describe("manifest model catalog planner", () => {
|
||||
},
|
||||
]);
|
||||
expect(plan.rows.map((row) => row.ref)).toEqual(["moonshot/kimi-k2.6"]);
|
||||
expect(plan.conflicts).toEqual([]);
|
||||
});
|
||||
|
||||
it("filters providers before row planning", () => {
|
||||
@@ -84,9 +85,10 @@ describe("manifest model catalog planner", () => {
|
||||
|
||||
expect(plan.entries.map((entry) => entry.pluginId)).toEqual(["openrouter"]);
|
||||
expect(plan.rows.map((row) => row.ref)).toEqual(["openrouter/anthropic/claude-sonnet-4.6"]);
|
||||
expect(plan.conflicts).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps the first registry row for duplicate provider/model keys", () => {
|
||||
it("reports duplicate provider/model keys and excludes conflicted rows", () => {
|
||||
const plan = planManifestModelCatalogRows({
|
||||
registry: {
|
||||
plugins: [
|
||||
@@ -95,7 +97,10 @@ describe("manifest model catalog planner", () => {
|
||||
modelCatalog: {
|
||||
providers: {
|
||||
openai: {
|
||||
models: [{ id: "gpt-5.4", name: "First GPT-5.4" }],
|
||||
models: [
|
||||
{ id: "gpt-5.4", name: "First GPT-5.4" },
|
||||
{ id: "gpt-5.5", name: "GPT-5.5" },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -115,10 +120,20 @@ describe("manifest model catalog planner", () => {
|
||||
});
|
||||
|
||||
expect(plan.entries).toHaveLength(2);
|
||||
expect(plan.conflicts).toEqual([
|
||||
{
|
||||
mergeKey: "openai::gpt-5.4",
|
||||
ref: "openai/gpt-5.4",
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.4",
|
||||
firstPluginId: "z-first",
|
||||
secondPluginId: "a-second",
|
||||
},
|
||||
]);
|
||||
expect(plan.rows).toHaveLength(1);
|
||||
expect(plan.rows[0]).toMatchObject({
|
||||
mergeKey: "openai::gpt-5.4",
|
||||
name: "First GPT-5.4",
|
||||
mergeKey: "openai::gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,9 +17,19 @@ export type ManifestModelCatalogPlanEntry = {
|
||||
rows: readonly NormalizedModelCatalogRow[];
|
||||
};
|
||||
|
||||
export type ManifestModelCatalogConflict = {
|
||||
mergeKey: string;
|
||||
ref: string;
|
||||
provider: string;
|
||||
modelId: string;
|
||||
firstPluginId: string;
|
||||
secondPluginId: string;
|
||||
};
|
||||
|
||||
export type ManifestModelCatalogPlan = {
|
||||
rows: readonly NormalizedModelCatalogRow[];
|
||||
entries: readonly ManifestModelCatalogPlanEntry[];
|
||||
conflicts: readonly ManifestModelCatalogConflict[];
|
||||
};
|
||||
|
||||
export function planManifestModelCatalogRows(params: {
|
||||
@@ -37,20 +47,36 @@ export function planManifestModelCatalogRows(params: {
|
||||
}
|
||||
}
|
||||
|
||||
const rows: NormalizedModelCatalogRow[] = [];
|
||||
const seenMergeKeys = new Set<string>();
|
||||
const rowCandidates: NormalizedModelCatalogRow[] = [];
|
||||
const seenRows = new Map<string, { pluginId: string; row: NormalizedModelCatalogRow }>();
|
||||
const conflicts = new Map<string, ManifestModelCatalogConflict>();
|
||||
for (const entry of entries) {
|
||||
for (const row of entry.rows) {
|
||||
if (seenMergeKeys.has(row.mergeKey)) {
|
||||
const seen = seenRows.get(row.mergeKey);
|
||||
if (seen) {
|
||||
if (!conflicts.has(row.mergeKey)) {
|
||||
conflicts.set(row.mergeKey, {
|
||||
mergeKey: row.mergeKey,
|
||||
ref: seen.row.ref,
|
||||
provider: seen.row.provider,
|
||||
modelId: seen.row.id,
|
||||
firstPluginId: seen.pluginId,
|
||||
secondPluginId: entry.pluginId,
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
seenMergeKeys.add(row.mergeKey);
|
||||
rows.push(row);
|
||||
seenRows.set(row.mergeKey, { pluginId: entry.pluginId, row });
|
||||
rowCandidates.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
const conflictedMergeKeys = new Set(conflicts.keys());
|
||||
const rows = rowCandidates.filter((row) => !conflictedMergeKeys.has(row.mergeKey));
|
||||
|
||||
return {
|
||||
entries,
|
||||
conflicts: [...conflicts.values()],
|
||||
rows: rows.toSorted(
|
||||
(left, right) =>
|
||||
left.provider.localeCompare(right.provider) || left.id.localeCompare(right.id),
|
||||
|
||||
Reference in New Issue
Block a user