fix: stabilize skills prompt ordering (#64198) (thanks @Bartok9)

This commit is contained in:
Peter Steinberger
2026-04-16 17:58:20 +01:00
parent c4488d5ef5
commit b31d243c57
4 changed files with 79 additions and 29 deletions

View File

@@ -372,23 +372,41 @@ describe("gateway-status command", () => {
it("surfaces unresolved SecretRef auth diagnostics when probe fails", async () => {
const { runtime, runtimeLogs, runtimeErrors } = createRuntimeCapture();
await withEnvAsync({ MISSING_GATEWAY_TOKEN: undefined }, async () => {
mockLocalTokenEnvRefConfig();
probeGateway.mockResolvedValueOnce({
ok: false,
url: "ws://127.0.0.1:18789",
connectLatencyMs: null,
error: "connection refused",
close: null,
health: null,
status: null,
presence: null,
configSnapshot: null,
const defaultReadBestEffortConfig = readBestEffortConfig.getMockImplementation();
const defaultProbeGateway = probeGateway.getMockImplementation();
try {
await withEnvAsync({ MISSING_GATEWAY_TOKEN: undefined }, async () => {
readBestEffortConfig.mockReset();
probeGateway.mockReset();
mockLocalTokenEnvRefConfig();
probeGateway.mockImplementation(async (opts: { url: string }) => {
const { url } = opts;
return {
ok: false,
url,
connectLatencyMs: null,
error: "connection refused",
close: null,
health: null,
status: null,
presence: null,
configSnapshot: null,
};
});
await expect(runGatewayStatus(runtime, { timeout: "1000", json: true })).rejects.toThrow(
"__exit__:1",
);
});
await expect(runGatewayStatus(runtime, { timeout: "1000", json: true })).rejects.toThrow(
"__exit__:1",
);
});
} finally {
readBestEffortConfig.mockReset();
if (defaultReadBestEffortConfig) {
readBestEffortConfig.mockImplementation(defaultReadBestEffortConfig);
}
probeGateway.mockReset();
if (defaultProbeGateway) {
probeGateway.mockImplementation(defaultProbeGateway);
}
}
expect(runtimeErrors).toHaveLength(0);
const unresolvedWarning = findUnresolvedSecretRefWarning(runtimeLogs);

View File

@@ -108,6 +108,21 @@ function loadVitestMusicGenerationFallbackEntries(
});
}
function loadVitestSpeechFallbackEntries(
pluginIds: readonly string[],
): SpeechProviderContractEntry[] {
return loadVitestCapabilityContractEntries({
contract: "speechProviders",
pluginSdkResolution: "src",
pluginIds,
pickEntries: (registry) =>
registry.speechProviders.map((entry) => ({
pluginId: entry.pluginId,
provider: entry.provider,
})),
});
}
function hasExplicitVideoGenerationModes(provider: VideoGenerationProviderPlugin): boolean {
return Boolean(
provider.capabilities.generate &&
@@ -156,7 +171,7 @@ function loadVitestCapabilityContractEntries<T>(params: {
}
export function loadVitestSpeechProviderContractRegistry(): SpeechProviderContractEntry[] {
return loadVitestCapabilityContractEntries({
const entries = loadVitestCapabilityContractEntries({
contract: "speechProviders",
pickEntries: (registry) =>
registry.speechProviders.map((entry) => ({
@@ -164,6 +179,19 @@ export function loadVitestSpeechProviderContractRegistry(): SpeechProviderContra
provider: entry.provider,
})),
});
const coveredPluginIds = new Set(entries.map((entry) => entry.pluginId));
const missingPluginIds = VITEST_CONTRACT_PLUGIN_IDS.speechProviders.filter(
(pluginId) => !coveredPluginIds.has(pluginId),
);
if (missingPluginIds.length === 0) {
return entries;
}
const replacementEntries = loadVitestSpeechFallbackEntries(missingPluginIds);
const replacedPluginIds = new Set(replacementEntries.map((entry) => entry.pluginId));
return [
...entries.filter((entry) => !replacedPluginIds.has(entry.pluginId)),
...replacementEntries,
];
}
export function loadVitestMediaUnderstandingProviderContractRegistry(): MediaUnderstandingProviderContractEntry[] {