From cbe2ec1244da4aac885ec9184ed07d363344bd86 Mon Sep 17 00:00:00 2001
From: Diego Rodrigues de Sa e Souza
<8016841+diegosouzapw@users.noreply.github.com>
Date: Fri, 3 Jul 2026 00:14:32 -0300
Subject: [PATCH] feat(dashboard): add tool-source diagnostics settings toggle
(#5978)
* feat(dashboard): add tool-source diagnostics settings toggle
Adds a Settings > Advanced card (cloned from DebugModeCard) that lets
operators flip the existing `logToolSources` flag from the UI instead
of editing the DB row directly. The backend gate (chatCore.ts) and DB
default were already present but had no toggle. Also adds
`logToolSources` to the /api/settings Zod PATCH schema (it is `.strict()`,
so the key was previously rejected) and en-only i18n strings.
Co-authored-by: DuyPrX <93126969+DuyPrX@users.noreply.github.com>
Inspired-by: https://github.com/decolua/9router/pull/1825
* chore(changelog): restore release entries + add tool-source toggle bullet
---------
Co-authored-by: DuyPrX <93126969+DuyPrX@users.noreply.github.com>
---
CHANGELOG.md | 1 +
.../dashboard/settings/advanced/page.tsx | 2 +
.../components/LogToolSourcesCard.tsx | 70 +++++++++++++++++++
src/i18n/messages/en.json | 2 +
src/shared/validation/settingsSchemas.ts | 1 +
tests/unit/settings-ui-layout-static.test.ts | 19 +++++
6 files changed, 95 insertions(+)
create mode 100644 src/app/(dashboard)/dashboard/settings/components/LogToolSourcesCard.tsx
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 (
+
+
+
+
+
+ troubleshoot
+
+
+
+
{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");