refactor(providers): tighten family outlier contracts

This commit is contained in:
Vincent Koc
2026-04-05 11:09:26 +09:00
parent 6ab1b43081
commit b56517b0ee
7 changed files with 174 additions and 66 deletions

View File

@@ -11,6 +11,12 @@ type SharedFamilyProviderInventory = {
sourceFiles: Set<string>;
};
type ExpectedSharedFamilyContract = {
replayFamilies?: readonly string[];
streamFamilies?: readonly string[];
toolCompatFamilies?: readonly string[];
};
const SRC_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
const REPO_ROOT = resolve(SRC_ROOT, "..");
const EXTENSIONS_DIR = resolve(REPO_ROOT, BUNDLED_PLUGIN_ROOT_DIR);
@@ -26,6 +32,54 @@ const PROVIDER_BOUNDARY_TEST_SIGNALS = [
/\bregister(?:Single)?ProviderPlugin\s*\(/u,
/\bcreateTestPluginApi\s*\(/u,
] as const;
const EXPECTED_SHARED_FAMILY_CONTRACTS: Record<string, ExpectedSharedFamilyContract> = {
"amazon-bedrock": {
replayFamilies: ["anthropic-by-model"],
},
"anthropic-vertex": {
replayFamilies: ["anthropic-by-model"],
},
google: {
replayFamilies: ["google-gemini"],
streamFamilies: ["google-thinking"],
toolCompatFamilies: ["gemini"],
},
kilocode: {
replayFamilies: ["passthrough-gemini"],
streamFamilies: ["kilocode-thinking"],
},
minimax: {
replayFamilies: ["hybrid-anthropic-openai"],
streamFamilies: ["minimax-fast-mode"],
},
moonshot: {
replayFamilies: ["openai-compatible"],
streamFamilies: ["moonshot-thinking"],
},
ollama: {
replayFamilies: ["openai-compatible"],
},
openai: {
streamFamilies: ["openai-responses-defaults"],
},
opencode: {
replayFamilies: ["passthrough-gemini"],
},
"opencode-go": {
replayFamilies: ["passthrough-gemini"],
},
openrouter: {
replayFamilies: ["passthrough-gemini"],
streamFamilies: ["openrouter-thinking"],
},
xai: {
replayFamilies: ["openai-compatible"],
},
zai: {
replayFamilies: ["openai-compatible"],
streamFamilies: ["tool-stream-default-on"],
},
};
function toRepoRelative(path: string): string {
return relative(REPO_ROOT, path).split(sep).join("/");
@@ -108,6 +162,50 @@ function collectProviderBoundaryTests(): Map<string, Set<string>> {
return inventory;
}
function listMatchingFamilies(source: string, pattern: RegExp): string[] {
return [...source.matchAll(pattern)].map((match) => match[1] ?? "");
}
function collectSharedFamilyAssignments(): Map<string, ExpectedSharedFamilyContract> {
const inventory = new Map<string, ExpectedSharedFamilyContract>();
const replayPattern =
/buildProviderReplayFamilyHooks\s*\(\s*\{\s*family:\s*"([^"]+)"/gu;
const streamPattern =
/buildProviderStreamFamilyHooks\s*\(\s*"([^"]+)"/gu;
const toolCompatPattern =
/buildProviderToolCompatFamilyHooks\s*\(\s*"([^"]+)"/gu;
for (const filePath of listFiles(EXTENSIONS_DIR)) {
if (!filePath.endsWith(".ts") || filePath.endsWith(".test.ts")) {
continue;
}
const source = readFileSync(filePath, "utf8");
const replayFamilies = listMatchingFamilies(source, replayPattern);
const streamFamilies = listMatchingFamilies(source, streamPattern);
const toolCompatFamilies = listMatchingFamilies(source, toolCompatPattern);
if (replayFamilies.length === 0 && streamFamilies.length === 0 && toolCompatFamilies.length === 0) {
continue;
}
const pluginId = resolveBundledPluginId(filePath);
if (!pluginId) {
continue;
}
const entry = inventory.get(pluginId) ?? {};
if (replayFamilies.length > 0) {
entry.replayFamilies = [...new Set([...(entry.replayFamilies ?? []), ...replayFamilies])].toSorted();
}
if (streamFamilies.length > 0) {
entry.streamFamilies = [...new Set([...(entry.streamFamilies ?? []), ...streamFamilies])].toSorted();
}
if (toolCompatFamilies.length > 0) {
entry.toolCompatFamilies = [...new Set([...(entry.toolCompatFamilies ?? []), ...toolCompatFamilies])].toSorted();
}
inventory.set(pluginId, entry);
}
return inventory;
}
describe("provider family plugin-boundary inventory", () => {
it("keeps shared-family provider hooks covered by at least one plugin-boundary test", () => {
const sharedFamilyProviders = collectSharedFamilyProviders();
@@ -123,4 +221,14 @@ describe("provider family plugin-boundary inventory", () => {
expect(missing).toEqual([]);
});
it("keeps shared-family assignments aligned with the curated provider inventory", () => {
const actualAssignments = Object.fromEntries(
[...collectSharedFamilyAssignments().entries()].toSorted(([left], [right]) =>
left.localeCompare(right),
),
);
expect(actualAssignments).toEqual(EXPECTED_SHARED_FAMILY_CONTRACTS);
});
});