diff --git a/CHANGELOG.md b/CHANGELOG.md index 18924ab581..e8c5054cd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - **feat(cli-tools):** add Crush CLI tool to the dashboard with one-click configuration. (thanks @dopaemon) - **feat(dashboard):** suggest HuggingFace Hub media models in the media provider view. (thanks @yicone) - **feat(dashboard):** collapse quota rows and sort by remaining quota in the usage view. (thanks @j2-cuong) +- **feat(dashboard):** add a settings toggle for tool-source diagnostics logging. (thanks @DuyPrX) ### 🔧 Bug Fixes diff --git a/src/app/(dashboard)/dashboard/settings/advanced/page.tsx b/src/app/(dashboard)/dashboard/settings/advanced/page.tsx index 803fbfe47c..5dfefd170b 100644 --- a/src/app/(dashboard)/dashboard/settings/advanced/page.tsx +++ b/src/app/(dashboard)/dashboard/settings/advanced/page.tsx @@ -1,6 +1,7 @@ "use client"; import DebugModeCard from "../components/DebugModeCard"; +import LogToolSourcesCard from "../components/LogToolSourcesCard"; import PayloadRulesTab from "../components/PayloadRulesTab"; import RequestLimitsTab from "../components/RequestLimitsTab"; import CliproxyapiSettingsTab from "../components/CliproxyapiSettingsTab"; @@ -9,6 +10,7 @@ export default function SettingsAdvancedPage() { return (
+ diff --git a/src/app/(dashboard)/dashboard/settings/components/LogToolSourcesCard.tsx b/src/app/(dashboard)/dashboard/settings/components/LogToolSourcesCard.tsx new file mode 100644 index 0000000000..d64575e993 --- /dev/null +++ b/src/app/(dashboard)/dashboard/settings/components/LogToolSourcesCard.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Card, Toggle } from "@/shared/components"; +import { useTranslations } from "next-intl"; + +export default function LogToolSourcesCard() { + const [logToolSources, setLogToolSources] = useState(false); + const [loading, setLoading] = useState(true); + const t = useTranslations("settings"); + + useEffect(() => { + let mounted = true; + + async function loadSettings() { + setLoading(true); + try { + const res = await fetch("/api/settings", { cache: "no-store" }); + if (res.ok && mounted) { + const data = await res.json(); + setLogToolSources(data.logToolSources === true); + } + } catch { + // Leave the current switch state in place if settings cannot be loaded. + } finally { + if (mounted) setLoading(false); + } + } + + loadSettings(); + return () => { + mounted = false; + }; + }, []); + + const updateLogToolSources = async (value: boolean) => { + const previousValue = logToolSources; + setLogToolSources(value); + try { + const res = await fetch("/api/settings", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ logToolSources: value }), + }); + if (!res.ok) setLogToolSources(previousValue); + } catch (err) { + setLogToolSources(previousValue); + console.error("Failed to update logToolSources:", err); + } + }; + + return ( + +
+
+
+ +
+
+

{t("logToolSourcesToggle")}

+

{t("logToolSourcesDescription")}

+
+
+ +
+
+ ); +} diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index b9189d9eb1..fa7bccd64b 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -4995,6 +4995,8 @@ "modelsDevInfoOrder": "User Override → models.dev → LiteLLM → Hardcoded Default", "systemTheme": "System Theme", "debugToggle": "Enable Debug Mode", + "logToolSourcesToggle": "Log Tool Sources", + "logToolSourcesDescription": "Emit a diagnostic log line per request summarizing tool count and MCP/hosted/client source breakdown.", "homePinProviderQuotaToHome": "Pin Information to Home Page", "homeProviderQuotaLimits": "Provider Quota Limits", "homeProviderQuotaLimitsDesc": "Pin the Provider Quota status container (with Refresh All button) to the top of the Home page.", diff --git a/src/shared/validation/settingsSchemas.ts b/src/shared/validation/settingsSchemas.ts index 3d53665875..2341b21c18 100644 --- a/src/shared/validation/settingsSchemas.ts +++ b/src/shared/validation/settingsSchemas.ts @@ -144,6 +144,7 @@ export const updateSettingsSchema = z.object({ .optional(), customBannedSignals: z.array(z.string().max(200)).optional(), debugMode: z.boolean().optional(), + logToolSources: z.boolean().optional(), hiddenSidebarItems: z.array(z.enum(HIDEABLE_SIDEBAR_ITEM_IDS)).optional(), hiddenSidebarGroupLabels: z.array(z.enum(HIDEABLE_SIDEBAR_GROUP_IDS)).optional(), sidebarSectionOrder: z diff --git a/tests/unit/settings-ui-layout-static.test.ts b/tests/unit/settings-ui-layout-static.test.ts index e9f50ee7a1..278b938d12 100644 --- a/tests/unit/settings-ui-layout-static.test.ts +++ b/tests/unit/settings-ui-layout-static.test.ts @@ -59,6 +59,25 @@ test("Debug mode moved to the top of Advanced settings", () => { assertInOrder(advancedPage, [" { + const advancedPage = readSrc("src/app/(dashboard)/dashboard/settings/advanced/page.tsx"); + + assertInOrder(advancedPage, [" { const proxyLogger = readSrc("src/shared/components/ProxyLogger.tsx"); const requestLogger = readSrc("src/shared/components/RequestLoggerV2.tsx");