Add daemon MCP injection toggle to settings

This commit is contained in:
Mohamed Boudra
2026-04-11 16:39:13 +07:00
parent fa552b0faa
commit 66bb8c6f04
2 changed files with 102 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
import { useCallback, useEffect, useMemo } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import type {
MutableDaemonConfig,
MutableDaemonConfigPatch,
} from "@server/shared/messages";
import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
export function daemonConfigQueryKey(serverId: string | null) {
return ["daemon-config", serverId] as const;
}
interface UseDaemonConfigResult {
config: MutableDaemonConfig | null;
isLoading: boolean;
patchConfig: (patch: MutableDaemonConfigPatch) => Promise<MutableDaemonConfig | undefined>;
}
export function useDaemonConfig(serverId: string | null): UseDaemonConfigResult {
const queryClient = useQueryClient();
const client = useHostRuntimeClient(serverId ?? "");
const isConnected = useHostRuntimeIsConnected(serverId ?? "");
const queryKey = useMemo(() => daemonConfigQueryKey(serverId), [serverId]);
const configQuery = useQuery({
queryKey,
enabled: Boolean(serverId && client && isConnected),
staleTime: Infinity,
queryFn: async () => {
if (!client) {
throw new Error("Host is not connected");
}
const result = await client.getDaemonConfig();
return result.config;
},
});
useEffect(() => {
if (!client || !isConnected || !serverId) {
return;
}
return client.on("status", (message) => {
if (message.type !== "status") {
return;
}
if (message.payload.status !== "daemon_config_changed") {
return;
}
queryClient.setQueryData(queryKey, message.payload.config as MutableDaemonConfig);
});
}, [client, isConnected, queryClient, queryKey, serverId]);
const patchConfig = useCallback(
async (patch: MutableDaemonConfigPatch) => {
if (!client) {
return undefined;
}
const result = await client.patchDaemonConfig(patch);
queryClient.setQueryData(queryKey, result.config);
return result.config;
},
[client, queryClient, queryKey],
);
return {
config: configQuery.data ?? null,
isLoading: configQuery.isLoading,
patchConfig,
};
}

View File

@@ -65,6 +65,7 @@ import { settingsStyles } from "@/styles/settings";
import { THINKING_TONE_NATIVE_PCM_BASE64 } from "@/utils/thinking-tone.native-pcm";
import { useVoiceAudioEngineOptional } from "@/contexts/voice-context";
import { useIsLocalDaemon } from "@/hooks/use-is-local-daemon";
import { useDaemonConfig } from "@/hooks/use-daemon-config";
import { useProvidersSnapshot } from "@/hooks/use-providers-snapshot";
import { useIsCompactFormFactor } from "@/constants/layout";
import { AGENT_PROVIDER_DEFINITIONS } from "@server/server/agent/provider-manifest";
@@ -360,6 +361,7 @@ function HostsSection(props: HostsSectionProps) {
}
interface GeneralSectionProps {
routeServerId: string;
settings: AppSettings;
handleThemeChange: (theme: AppSettings["theme"]) => void;
handleSendBehaviorChange: (behavior: SendBehavior) => void;
@@ -404,11 +406,14 @@ const THEME_LABELS: Record<AppSettings["theme"], string> = {
};
function GeneralSection({
routeServerId,
settings,
handleThemeChange,
handleSendBehaviorChange,
}: GeneralSectionProps) {
const { theme } = useUnistyles();
const isConnected = useHostRuntimeIsConnected(routeServerId);
const { config, patchConfig } = useDaemonConfig(routeServerId);
const iconSize = theme.iconSize.md;
const iconColor = theme.colors.foregroundMuted;
@@ -475,6 +480,31 @@ function GeneralSection({
]}
/>
</View>
{routeServerId.length > 0 && isConnected ? (
<View style={[styles.audioRow, styles.audioRowBorder]}>
<View style={styles.audioRowContent}>
<Text style={styles.audioRowTitle}>Inject Paseo tools</Text>
<Text style={styles.audioRowSubtitle}>
Automatically inject Paseo MCP tools into new agents
</Text>
</View>
<SegmentedControl
size="sm"
value={config?.mcp.injectIntoAgents === false ? "off" : "on"}
onValueChange={(value) => {
void patchConfig({
mcp: {
injectIntoAgents: value === "on",
},
});
}}
options={[
{ value: "on", label: "On" },
{ value: "off", label: "Off" },
]}
/>
</View>
) : null}
</View>
</View>
);
@@ -1107,6 +1137,7 @@ export default function SettingsScreen() {
};
const generalProps: GeneralSectionProps = {
routeServerId,
settings,
handleThemeChange,
handleSendBehaviorChange,