+
+
+
+ {t("web_search_description")}
+
+
+
+ {healthData && (
+
+
+
+ {isHealthy
+ ? `${t("web_search_status_healthy")} (${healthData.response_time_ms}ms)`
+ : isUnavailable
+ ? t("web_search_status_not_configured")
+ : t("web_search_status_unhealthy")}
+
+
+ )}
+
+
+
+ {t("web_search_title")}
+
+ {t("web_search_enabled_description")}
+
+
+
+
+
+
+
+ {t("web_search_enabled_description")}
+
+
+
+
+
+ {enabled && (
+
+
+
+
setEngines(e.target.value)}
+ className="text-sm md:text-base h-9 md:h-10"
+ />
+
+ {t("web_search_engines_description")}
+
+
+
+
+
+
+
setLanguage(e.target.value)}
+ className="text-sm md:text-base h-9 md:h-10"
+ />
+
+ {t("web_search_language_description")}
+
+
+
+
+
+
+
+ {t("web_search_safesearch_description")}
+
+
+
+
+ )}
+
+
+
+
+
+
+
+ );
+}
diff --git a/surfsense_web/contracts/types/search-space.types.ts b/surfsense_web/contracts/types/search-space.types.ts
index aed08710e..a71c1bbbb 100644
--- a/surfsense_web/contracts/types/search-space.types.ts
+++ b/surfsense_web/contracts/types/search-space.types.ts
@@ -9,6 +9,8 @@ export const searchSpace = z.object({
user_id: z.string(),
citations_enabled: z.boolean(),
qna_custom_instructions: z.string().nullable(),
+ web_search_enabled: z.boolean(),
+ web_search_config: z.record(z.unknown()).nullable(),
member_count: z.number(),
is_owner: z.boolean(),
});
@@ -49,7 +51,14 @@ export const getSearchSpaceResponse = searchSpace.omit({ member_count: true, is_
export const updateSearchSpaceRequest = z.object({
id: z.number(),
data: searchSpace
- .pick({ name: true, description: true, citations_enabled: true, qna_custom_instructions: true })
+ .pick({
+ name: true,
+ description: true,
+ citations_enabled: true,
+ qna_custom_instructions: true,
+ web_search_enabled: true,
+ web_search_config: true,
+ })
.partial(),
});
diff --git a/surfsense_web/messages/en.json b/surfsense_web/messages/en.json
index d6ad50f29..a454ea5c9 100644
--- a/surfsense_web/messages/en.json
+++ b/surfsense_web/messages/en.json
@@ -757,7 +757,27 @@
"general_reset": "Reset Changes",
"general_save": "Save Changes",
"general_saving": "Saving",
- "general_unsaved_changes": "You have unsaved changes. Click \"Save Changes\" to apply them."
+ "general_unsaved_changes": "You have unsaved changes. Click \"Save Changes\" to apply them.",
+ "nav_web_search": "Web Search",
+ "nav_web_search_desc": "Built-in web search settings",
+ "web_search_title": "Web Search",
+ "web_search_description": "Web search is powered by a built-in SearXNG instance. All queries are proxied through your server — no data is sent to third parties.",
+ "web_search_enabled_label": "Enable Web Search",
+ "web_search_enabled_description": "When enabled, the AI agent can search the web for real-time information like news, prices, and current events.",
+ "web_search_status_healthy": "Web search service is healthy",
+ "web_search_status_unhealthy": "Web search service is unavailable",
+ "web_search_status_not_configured": "Web search service is not configured",
+ "web_search_engines_label": "Search Engines",
+ "web_search_engines_placeholder": "google,brave,duckduckgo",
+ "web_search_engines_description": "Comma-separated list of SearXNG engines to use. Leave empty for defaults.",
+ "web_search_language_label": "Preferred Language",
+ "web_search_language_placeholder": "en",
+ "web_search_language_description": "IETF language tag (e.g. en, en-US). Leave empty for auto-detect.",
+ "web_search_safesearch_label": "SafeSearch Level",
+ "web_search_safesearch_description": "0 = off, 1 = moderate, 2 = strict",
+ "web_search_save": "Save Web Search Settings",
+ "web_search_saving": "Saving...",
+ "web_search_saved": "Web search settings saved"
},
"homepage": {
"hero_title_part1": "The AI Workspace",