




















@@ -1564,4 +1564,94 @@ describe("runtime web tools resolution", () => {
15641564expect(resolveBundledWebFetchProvidersFromPublicArtifactsMock).not.toHaveBeenCalled();
15651565expect(resolvePluginWebFetchProvidersMock).not.toHaveBeenCalled();
15661566});
1567+1568+describe("when brave is installed as an external plugin and explicitly configured", () => {
1569+const externalBraveImpl = ({
1570+ value,
1571+ origin,
1572+}: {
1573+value: string;
1574+origin?: string;
1575+}): string | undefined => {
1576+if (origin === "bundled" && value === "brave") {
1577+return undefined;
1578+}
1579+return (
1580+{
1581+brave: "brave",
1582+firecrawl: "firecrawl",
1583+gemini: "google",
1584+grok: "xai",
1585+kimi: "moonshot",
1586+perplexity: "perplexity",
1587+} as Record<string, string | undefined>
1588+)[value];
1589+};
1590+1591+const defaultImpl = ({ value }: { value: string }): string | undefined =>
1592+(
1593+({
1594+brave: "brave",
1595+firecrawl: "firecrawl",
1596+gemini: "google",
1597+grok: "xai",
1598+kimi: "moonshot",
1599+perplexity: "perplexity",
1600+}) as Record<string, string | undefined>
1601+)[value];
1602+1603+beforeEach(() => {
1604+loadInstalledPluginIndexInstallRecordsSyncMock.mockReturnValue({
1605+brave: { source: "npm", spec: "@openclaw/brave-search" },
1606+});
1607+resolveManifestContractOwnerPluginIdMock.mockImplementation(externalBraveImpl);
1608+});
1609+1610+afterEach(() => {
1611+resolveManifestContractOwnerPluginIdMock.mockImplementation(defaultImpl);
1612+});
1613+1614+it("selects the configured provider without re-invoking provider discovery when found in the first pass", async () => {
1615+resolvePluginWebSearchProvidersMock
1616+.mockReturnValueOnce(buildTestWebSearchProviders())
1617+.mockReturnValueOnce([]);
1618+1619+const { metadata, context } = await runRuntimeWebTools({
1620+config: asConfig({
1621+tools: {
1622+web: {
1623+search: {
1624+provider: "brave",
1625+},
1626+},
1627+},
1628+plugins: {
1629+entries: {
1630+brave: {
1631+config: {
1632+webSearch: {
1633+apiKey: "brave-api-key", // pragma: allowlist secret
1634+},
1635+},
1636+},
1637+},
1638+},
1639+}),
1640+});
1641+1642+expect(metadata.search.selectedProvider).toBe("brave");
1643+expect(metadata.search.providerSource).toBe("configured");
1644+expect(metadata.search.selectedProviderKeySource).toBe("config");
1645+expect(context.warnings).not.toEqual(
1646+expect.arrayContaining([
1647+expect.objectContaining({ code: "WEB_SEARCH_PROVIDER_INVALID_AUTODETECT" }),
1648+]),
1649+);
1650+expect(resolvePluginWebSearchProvidersMock).toHaveBeenCalledTimes(1);
1651+expect(
1652+resolveBundledExplicitWebSearchProvidersFromPublicArtifactsMock,
1653+).not.toHaveBeenCalled();
1654+expect(resolveBundledWebSearchProvidersFromPublicArtifactsMock).not.toHaveBeenCalled();
1655+});
1656+});
15671657});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。