Fix configure cache ownership for plugin resolvers (#52018)

* fix configure cache ownership

* address web-search cache review

* rekey provider wizard cache

* honor plugin cache opt-outs

* fix cache invalidation gaps

* align plugin snapshot ttl

* refresh snapshot cache keys
This commit is contained in:
Tak Hoffman
2026-03-21 23:41:45 -05:00
committed by GitHub
parent ec59974a46
commit 0f6dbb4390
6 changed files with 782 additions and 55 deletions

View File

@@ -146,6 +146,7 @@ describe("runConfigureWizard", () => {
]);
mocks.applySearchKey.mockReset();
mocks.applySearchProviderSelection.mockReset();
mocks.applySearchProviderSelection.mockImplementation((cfg: OpenClawConfig) => cfg);
});
it("persists gateway.mode=local when only the run mode is selected", async () => {
@@ -377,56 +378,66 @@ describe("runConfigureWizard", () => {
});
it("uses provider-specific credential copy for Gemini web search", async () => {
mocks.readConfigFileSnapshot.mockResolvedValue({
exists: false,
valid: true,
config: {},
issues: [],
});
mocks.resolveGatewayPort.mockReturnValue(18789);
mocks.probeGatewayReachable.mockResolvedValue({ ok: false });
mocks.resolveControlUiLinks.mockReturnValue({ wsUrl: "ws://127.0.0.1:18789" });
mocks.summarizeExistingConfig.mockReturnValue("");
mocks.createClackPrompter.mockReturnValue({});
mocks.resolveSearchProviderOptions.mockReturnValue([
{
id: "gemini",
label: "Gemini (Google Search)",
hint: "Requires Google Gemini API key · Google Search grounding",
credentialLabel: "Google Gemini API key",
envVars: ["GEMINI_API_KEY"],
placeholder: "AIza...",
signupUrl: "https://aistudio.google.com/apikey",
credentialPath: "plugins.entries.google.config.webSearch.apiKey",
},
]);
const originalGeminiApiKey = process.env.GEMINI_API_KEY;
delete process.env.GEMINI_API_KEY;
try {
mocks.readConfigFileSnapshot.mockResolvedValue({
exists: false,
valid: true,
config: {},
issues: [],
});
mocks.resolveGatewayPort.mockReturnValue(18789);
mocks.probeGatewayReachable.mockResolvedValue({ ok: false });
mocks.resolveControlUiLinks.mockReturnValue({ wsUrl: "ws://127.0.0.1:18789" });
mocks.summarizeExistingConfig.mockReturnValue("");
mocks.createClackPrompter.mockReturnValue({});
mocks.resolveSearchProviderOptions.mockReturnValue([
{
id: "gemini",
label: "Gemini (Google Search)",
hint: "Requires Google Gemini API key · Google Search grounding",
credentialLabel: "Google Gemini API key",
envVars: ["GEMINI_API_KEY"],
placeholder: "AIza...",
signupUrl: "https://aistudio.google.com/apikey",
credentialPath: "plugins.entries.google.config.webSearch.apiKey",
},
]);
const selectQueue = ["local", "gemini"];
const confirmQueue = [true, false];
mocks.clackSelect.mockImplementation(async () => selectQueue.shift());
mocks.clackConfirm.mockImplementation(async () => confirmQueue.shift());
mocks.clackText.mockResolvedValue("");
mocks.clackIntro.mockResolvedValue(undefined);
mocks.clackOutro.mockResolvedValue(undefined);
const selectQueue = ["local", "gemini"];
const confirmQueue = [true, false];
mocks.clackSelect.mockImplementation(async () => selectQueue.shift());
mocks.clackConfirm.mockImplementation(async () => confirmQueue.shift());
mocks.clackText.mockResolvedValue("");
mocks.clackIntro.mockResolvedValue(undefined);
mocks.clackOutro.mockResolvedValue(undefined);
await runConfigureWizard(
{ command: "configure", sections: ["web"] },
{
log: vi.fn(),
error: vi.fn(),
exit: vi.fn(),
},
);
await runConfigureWizard(
{ command: "configure", sections: ["web"] },
{
log: vi.fn(),
error: vi.fn(),
exit: vi.fn(),
},
);
expect(mocks.clackText).toHaveBeenCalledWith(
expect.objectContaining({
message: "Google Gemini API key",
}),
);
expect(mocks.note).toHaveBeenCalledWith(
expect.stringContaining("Store your Google Gemini API key here or set GEMINI_API_KEY"),
"Web search",
);
expect(mocks.clackText).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining("Google Gemini API key"),
}),
);
expect(mocks.note).toHaveBeenCalledWith(
expect.stringContaining("Store your Google Gemini API key here or set GEMINI_API_KEY"),
"Web search",
);
} finally {
if (originalGeminiApiKey === undefined) {
delete process.env.GEMINI_API_KEY;
} else {
process.env.GEMINI_API_KEY = originalGeminiApiKey;
}
}
});
it("does not crash when web search providers are unavailable under plugin policy", async () => {