Add daemon MCP injection toggle to settings
This commit is contained in:
@@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -65,6 +65,7 @@ import { settingsStyles } from "@/styles/settings";
|
|||||||
import { THINKING_TONE_NATIVE_PCM_BASE64 } from "@/utils/thinking-tone.native-pcm";
|
import { THINKING_TONE_NATIVE_PCM_BASE64 } from "@/utils/thinking-tone.native-pcm";
|
||||||
import { useVoiceAudioEngineOptional } from "@/contexts/voice-context";
|
import { useVoiceAudioEngineOptional } from "@/contexts/voice-context";
|
||||||
import { useIsLocalDaemon } from "@/hooks/use-is-local-daemon";
|
import { useIsLocalDaemon } from "@/hooks/use-is-local-daemon";
|
||||||
|
import { useDaemonConfig } from "@/hooks/use-daemon-config";
|
||||||
import { useProvidersSnapshot } from "@/hooks/use-providers-snapshot";
|
import { useProvidersSnapshot } from "@/hooks/use-providers-snapshot";
|
||||||
import { useIsCompactFormFactor } from "@/constants/layout";
|
import { useIsCompactFormFactor } from "@/constants/layout";
|
||||||
import { AGENT_PROVIDER_DEFINITIONS } from "@server/server/agent/provider-manifest";
|
import { AGENT_PROVIDER_DEFINITIONS } from "@server/server/agent/provider-manifest";
|
||||||
@@ -360,6 +361,7 @@ function HostsSection(props: HostsSectionProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface GeneralSectionProps {
|
interface GeneralSectionProps {
|
||||||
|
routeServerId: string;
|
||||||
settings: AppSettings;
|
settings: AppSettings;
|
||||||
handleThemeChange: (theme: AppSettings["theme"]) => void;
|
handleThemeChange: (theme: AppSettings["theme"]) => void;
|
||||||
handleSendBehaviorChange: (behavior: SendBehavior) => void;
|
handleSendBehaviorChange: (behavior: SendBehavior) => void;
|
||||||
@@ -404,11 +406,14 @@ const THEME_LABELS: Record<AppSettings["theme"], string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function GeneralSection({
|
function GeneralSection({
|
||||||
|
routeServerId,
|
||||||
settings,
|
settings,
|
||||||
handleThemeChange,
|
handleThemeChange,
|
||||||
handleSendBehaviorChange,
|
handleSendBehaviorChange,
|
||||||
}: GeneralSectionProps) {
|
}: GeneralSectionProps) {
|
||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
|
const isConnected = useHostRuntimeIsConnected(routeServerId);
|
||||||
|
const { config, patchConfig } = useDaemonConfig(routeServerId);
|
||||||
const iconSize = theme.iconSize.md;
|
const iconSize = theme.iconSize.md;
|
||||||
const iconColor = theme.colors.foregroundMuted;
|
const iconColor = theme.colors.foregroundMuted;
|
||||||
|
|
||||||
@@ -475,6 +480,31 @@ function GeneralSection({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</View>
|
</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>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@@ -1107,6 +1137,7 @@ export default function SettingsScreen() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const generalProps: GeneralSectionProps = {
|
const generalProps: GeneralSectionProps = {
|
||||||
|
routeServerId,
|
||||||
settings,
|
settings,
|
||||||
handleThemeChange,
|
handleThemeChange,
|
||||||
handleSendBehaviorChange,
|
handleSendBehaviorChange,
|
||||||
|
|||||||
Reference in New Issue
Block a user