feat(FN-3901): add builtin research web-search provider as default

The merge adds a builtin web-search research provider as the default, replacing the need for external research provider configuration and removing the setup gate for builtin defaults. Dashboard settings UX for research defaults was aligned (ResearchView, SettingsModal), CLI research commands were up

Fusion-Task-Id: FN-3901
This commit is contained in:
Fusion
2026-05-09 19:37:31 -07:00
committed by gsxdsm
parent 1caed5c586
commit d25e8cbfa9
21 changed files with 493 additions and 187 deletions

View File

@@ -82,6 +82,21 @@ describe("research commands", () => {
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("Created research run"));
});
it("creates a run when provider is unset by defaulting to builtin", async () => {
storeMock.getSettings.mockResolvedValueOnce({ researchSettings: { enabled: true } });
resolveResearchSettingsMock.mockReturnValueOnce({
enabled: true,
searchProvider: "builtin",
limits: { maxConcurrentRuns: 2, maxSourcesPerRun: 5, requestTimeoutMs: 1000, maxDurationMs: 5000 },
});
providerRegistryMock.mockReturnValueOnce({ getAvailableProviders: () => ["web-search"], getProvider: () => ({ type: "web-search" }) });
await runResearchCreate({ query: "hello builtin" });
expect(orchestratorMock.createRun).toHaveBeenCalled();
expect(errorSpy).not.toHaveBeenCalled();
});
it("lists runs as json", async () => {
await runResearchList({ json: true, status: "completed", limit: 3 });
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('"runs"'));

View File

@@ -42,7 +42,8 @@ async function getStore(projectName?: string): Promise<TaskStore> {
}
function hasProviderCredentials(settings: Awaited<ReturnType<TaskStore["getSettings"]>>, providerId: string | undefined): boolean {
if (!providerId) return false;
if (!providerId || providerId === "builtin") return true;
if (providerId === "none") return false;
if (providerId === "searxng") return Boolean(settings.researchGlobalSearxngUrl);
if (providerId === "brave") return Boolean(settings.researchGlobalBraveApiKey);
if (providerId === "google") return Boolean(settings.researchGlobalGoogleSearchApiKey && settings.researchGlobalGoogleSearchCx);
@@ -57,11 +58,8 @@ async function getResearchRuntime(store: TaskStore) {
throw new Error("feature-disabled: Research is disabled in settings.");
}
const configuredProvider = (resolved.searchProvider as string | undefined) ?? settings.researchGlobalWebSearchProvider;
if (!configuredProvider) {
throw new Error("provider-unavailable: Research providers are not configured. Add provider credentials in settings.");
}
if (!hasProviderCredentials(settings, configuredProvider)) {
const configuredProvider = (resolved.searchProvider as string | undefined) ?? settings.researchGlobalWebSearchProvider ?? "builtin";
if (configuredProvider !== "builtin" && configuredProvider !== "none" && !hasProviderCredentials(settings, configuredProvider)) {
throw new Error(`missing-credentials: ${configuredProvider} credentials are missing. Configure Authentication and Research defaults in settings.`);
}