mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 12:17:45 +02:00
[hAIk]: integrate settings backend-bridge into frontend: move AppSettings and CustomProvider interfaces into settings bridge with proper return types, switch Main.tsx to GET_SETTINGS, useSettings.ts to UPDATE_SETTINGS, GeneralTab.tsx to RESET_SYSTEM_PROMPT — all importing directly from the bridge
This commit is contained in:
@@ -4,7 +4,7 @@ import { HashRouter, Routes, Route } from 'react-router-dom';
|
||||
import { ThemeProvider as MuiThemeProvider, CssBaseline } from '@mui/material';
|
||||
import { store } from '../shared/state/store';
|
||||
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
|
||||
import { fetchSettings } from '@/shared/state/settingsSlice';
|
||||
import { GET_SETTINGS } from '@/shared/backend-bridge/apps/settings';
|
||||
import { fetchModels } from '@/shared/state/modelsSlice';
|
||||
import {
|
||||
setAppVersion,
|
||||
@@ -40,7 +40,7 @@ const SettingsLoader: React.FC<{ children: React.ReactNode }> = ({ children }) =
|
||||
const theme = useAppSelector((s) => s.settings.data.theme);
|
||||
const loaded = useAppSelector((s) => s.settings.loaded);
|
||||
useEffect(() => {
|
||||
dispatch(fetchSettings());
|
||||
dispatch(GET_SETTINGS());
|
||||
dispatch(fetchModels());
|
||||
}, [dispatch]);
|
||||
useEffect(() => {
|
||||
|
||||
@@ -10,7 +10,8 @@ import Switch from '@mui/material/Switch';
|
||||
import FolderOpenIcon from '@mui/icons-material/FolderOpen';
|
||||
import LanguageIcon from '@mui/icons-material/Language';
|
||||
import RestartAltIcon from '@mui/icons-material/RestartAlt';
|
||||
import { DEFAULT_SYSTEM_PROMPT, resetSystemPrompt } from '@/shared/state/settingsSlice';
|
||||
import { RESET_SYSTEM_PROMPT } from '@/shared/backend-bridge/apps/settings';
|
||||
import { DEFAULT_SYSTEM_PROMPT } from '@/shared/state/settingsSlice';
|
||||
import InterfaceSection from './InterfaceSection';
|
||||
import AboutSection from './AboutSection';
|
||||
import type { UseSettingsReturn } from './hooks/useSettings';
|
||||
@@ -29,7 +30,7 @@ const GeneralTab: React.FC<{ s: UseSettingsReturn }> = ({ s }) => {
|
||||
size="small"
|
||||
startIcon={<RestartAltIcon sx={{ fontSize: 14 }} />}
|
||||
onClick={async () => {
|
||||
await dispatch(resetSystemPrompt());
|
||||
await dispatch(RESET_SYSTEM_PROMPT());
|
||||
setForm((prev) => ({ ...prev, default_system_prompt: DEFAULT_SYSTEM_PROMPT }));
|
||||
}}
|
||||
sx={{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useMemo, useCallback } from 'react';
|
||||
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
|
||||
import { updateSettings, closeSettingsModal, AppSettings } from '@/shared/state/settingsSlice';
|
||||
import { UPDATE_SETTINGS, AppSettings } from '@/shared/backend-bridge/apps/settings';
|
||||
import { closeSettingsModal } from '@/shared/state/settingsSlice';
|
||||
import { fetchModels } from '@/shared/state/modelsSlice';
|
||||
import { setChecking, setUpdateError } from '@/shared/state/updateSlice';
|
||||
import { LIST_MODES } from '@/shared/state/modesSlice';
|
||||
@@ -33,7 +34,7 @@ export function useSettings() {
|
||||
useEffect(() => { if (loaded) setForm({ ...settings }); }, [loaded, settings]);
|
||||
const hasChanges = JSON.stringify(form) !== JSON.stringify(settings);
|
||||
const handleSave = async () => {
|
||||
await dispatch(updateSettings(form));
|
||||
await dispatch(UPDATE_SETTINGS(form));
|
||||
if (form.theme !== settings.theme) setThemeMode(form.theme);
|
||||
dispatch(fetchModels());
|
||||
setSaved(true);
|
||||
@@ -48,7 +49,7 @@ export function useSettings() {
|
||||
dispatch(closeSettingsModal());
|
||||
}, [settings, dispatch]);
|
||||
const handleSaveAndClose = useCallback(async () => {
|
||||
await dispatch(updateSettings(form));
|
||||
await dispatch(UPDATE_SETTINGS(form));
|
||||
if (form.theme !== settings.theme) setThemeMode(form.theme);
|
||||
dispatch(fetchModels());
|
||||
setSaved(true);
|
||||
|
||||
@@ -3,19 +3,51 @@ import { API_BASE } from '@/shared/backend-bridge/base_routes';
|
||||
|
||||
const SETTINGS_API: string = `${API_BASE}/settings`;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface CustomProvider {
|
||||
name: string;
|
||||
base_url: string;
|
||||
api_key: string;
|
||||
models: Array<{ value: string; label: string; context_window?: number }>;
|
||||
}
|
||||
|
||||
export interface AppSettings {
|
||||
default_system_prompt: string | null;
|
||||
default_folder: string | null;
|
||||
default_model: string;
|
||||
default_mode: string;
|
||||
default_max_turns: number | null;
|
||||
zoom_sensitivity: number;
|
||||
theme: 'light' | 'dark';
|
||||
new_agent_shortcut: string;
|
||||
anthropic_api_key: string | null;
|
||||
openai_api_key?: string | null;
|
||||
google_api_key?: string | null;
|
||||
openrouter_api_key?: string | null;
|
||||
custom_providers?: CustomProvider[];
|
||||
browser_homepage: string;
|
||||
auto_select_mode_on_new_agent: boolean;
|
||||
expand_new_chats_in_dashboard: boolean;
|
||||
auto_reveal_sub_agents: boolean;
|
||||
dev_mode: boolean;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Settings
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
const get_settings_endpoint: string = SETTINGS_API;
|
||||
async function get_settings_function(): Promise<Record<string, unknown>> {
|
||||
async function get_settings_function(): Promise<AppSettings> {
|
||||
const res = await fetch(get_settings_endpoint, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
const data = await res.json();
|
||||
return data as Record<string, unknown>;
|
||||
return data as AppSettings;
|
||||
}
|
||||
export const GET_SETTINGS = createAsyncThunk(
|
||||
get_settings_endpoint,
|
||||
@@ -24,29 +56,14 @@ export const GET_SETTINGS = createAsyncThunk(
|
||||
|
||||
|
||||
const update_settings_endpoint: string = SETTINGS_API;
|
||||
async function update_settings_function(body: {
|
||||
default_system_prompt?: string;
|
||||
default_folder?: string | null;
|
||||
default_model?: string;
|
||||
default_mode?: string;
|
||||
default_max_turns?: number | null;
|
||||
anthropic_api_key?: string | null;
|
||||
zoom_sensitivity?: number;
|
||||
theme?: string;
|
||||
new_agent_shortcut?: string;
|
||||
browser_homepage?: string;
|
||||
auto_select_mode_on_new_agent?: boolean;
|
||||
expand_new_chats_in_dashboard?: boolean;
|
||||
auto_reveal_sub_agents?: boolean;
|
||||
dev_mode?: boolean;
|
||||
}): Promise<{ ok: boolean; settings: Record<string, unknown> }> {
|
||||
async function update_settings_function(body: Partial<AppSettings>): Promise<{ ok: boolean; settings: AppSettings }> {
|
||||
const res = await fetch(update_settings_endpoint, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data as { ok: boolean; settings: Record<string, unknown> };
|
||||
return data as { ok: boolean; settings: AppSettings };
|
||||
}
|
||||
export const UPDATE_SETTINGS = createAsyncThunk(
|
||||
update_settings_endpoint,
|
||||
@@ -55,13 +72,13 @@ export const UPDATE_SETTINGS = createAsyncThunk(
|
||||
|
||||
|
||||
const reset_system_prompt_endpoint: string = `${SETTINGS_API}/reset-system-prompt`;
|
||||
async function reset_system_prompt_function(): Promise<{ ok: boolean; settings: Record<string, unknown> }> {
|
||||
async function reset_system_prompt_function(): Promise<{ ok: boolean; settings: AppSettings }> {
|
||||
const res = await fetch(reset_system_prompt_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
const data = await res.json();
|
||||
return data as { ok: boolean; settings: Record<string, unknown> };
|
||||
return data as { ok: boolean; settings: AppSettings };
|
||||
}
|
||||
export const RESET_SYSTEM_PROMPT = createAsyncThunk(
|
||||
reset_system_prompt_endpoint,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { API_BASE } from '@/shared/config';
|
||||
|
||||
const SETTINGS_API = `${API_BASE}/settings`;
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import {
|
||||
GET_SETTINGS,
|
||||
UPDATE_SETTINGS,
|
||||
RESET_SYSTEM_PROMPT,
|
||||
} from '@/shared/backend-bridge/apps/settings';
|
||||
import type { AppSettings } from '@/shared/backend-bridge/apps/settings';
|
||||
|
||||
export const DEFAULT_SYSTEM_PROMPT =
|
||||
`You are a personal AI assistant running inside OpenSwarm.\n\n` +
|
||||
@@ -20,34 +23,6 @@ export const DEFAULT_SYSTEM_PROMPT =
|
||||
`make reasonable assumptions and act. If you need to ask, use the AskUserQuestion tool.\n` +
|
||||
`Do not over-explain what you are about to do. Just do it and show the results.`;
|
||||
|
||||
export interface CustomProvider {
|
||||
name: string;
|
||||
base_url: string;
|
||||
api_key: string;
|
||||
models: Array<{ value: string; label: string; context_window?: number }>;
|
||||
}
|
||||
|
||||
export interface AppSettings {
|
||||
default_system_prompt: string | null;
|
||||
default_folder: string | null;
|
||||
default_model: string;
|
||||
default_mode: string;
|
||||
default_max_turns: number | null;
|
||||
zoom_sensitivity: number;
|
||||
theme: 'light' | 'dark';
|
||||
new_agent_shortcut: string;
|
||||
anthropic_api_key: string | null;
|
||||
openai_api_key?: string | null;
|
||||
google_api_key?: string | null;
|
||||
openrouter_api_key?: string | null;
|
||||
custom_providers?: CustomProvider[];
|
||||
browser_homepage: string;
|
||||
auto_select_mode_on_new_agent: boolean;
|
||||
expand_new_chats_in_dashboard: boolean;
|
||||
auto_reveal_sub_agents: boolean;
|
||||
dev_mode: boolean;
|
||||
}
|
||||
|
||||
export interface BrowseResult {
|
||||
current: string;
|
||||
parent: string | null;
|
||||
@@ -84,33 +59,6 @@ const initialState: SettingsState = {
|
||||
modalOpen: false,
|
||||
};
|
||||
|
||||
export const fetchSettings = createAsyncThunk('settings/fetch', async () => {
|
||||
const res = await fetch(SETTINGS_API);
|
||||
return (await res.json()) as AppSettings;
|
||||
});
|
||||
|
||||
export const updateSettings = createAsyncThunk(
|
||||
'settings/update',
|
||||
async (settings: AppSettings) => {
|
||||
const res = await fetch(SETTINGS_API, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(settings),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.settings as AppSettings;
|
||||
}
|
||||
);
|
||||
|
||||
export const resetSystemPrompt = createAsyncThunk(
|
||||
'settings/resetSystemPrompt',
|
||||
async () => {
|
||||
const res = await fetch(`${SETTINGS_API}/reset-system-prompt`, { method: 'POST' });
|
||||
const data = await res.json();
|
||||
return data.settings as AppSettings;
|
||||
}
|
||||
);
|
||||
|
||||
const settingsSlice = createSlice({
|
||||
name: 'settings',
|
||||
initialState,
|
||||
@@ -124,23 +72,23 @@ const settingsSlice = createSlice({
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(fetchSettings.pending, (state) => {
|
||||
.addCase(GET_SETTINGS.pending, (state) => {
|
||||
state.loading = true;
|
||||
})
|
||||
.addCase(fetchSettings.fulfilled, (state, action) => {
|
||||
.addCase(GET_SETTINGS.fulfilled, (state, action) => {
|
||||
state.loading = false;
|
||||
state.loaded = true;
|
||||
state.data = action.payload;
|
||||
})
|
||||
.addCase(fetchSettings.rejected, (state) => {
|
||||
.addCase(GET_SETTINGS.rejected, (state) => {
|
||||
state.loading = false;
|
||||
state.loaded = true;
|
||||
})
|
||||
.addCase(updateSettings.fulfilled, (state, action) => {
|
||||
state.data = action.payload;
|
||||
.addCase(UPDATE_SETTINGS.fulfilled, (state, action) => {
|
||||
state.data = action.payload.settings;
|
||||
})
|
||||
.addCase(resetSystemPrompt.fulfilled, (state, action) => {
|
||||
state.data = action.payload;
|
||||
.addCase(RESET_SYSTEM_PROMPT.fulfilled, (state, action) => {
|
||||
state.data = action.payload.settings;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user