From 5fc9d69310e58d69e6bbcc22bffc908a2e9d7aff Mon Sep 17 00:00:00 2001 From: ycjcl868 Date: Thu, 20 Mar 2025 14:54:08 +0800 Subject: [PATCH 1/3] feat(settings): add store --- apps/agent-tars/package.json | 1 + .../agent-tars/src/main/customTools/search.ts | 11 +-- apps/agent-tars/src/main/ipcRoutes/llm.ts | 9 +- apps/agent-tars/src/main/ipcRoutes/search.ts | 8 +- apps/agent-tars/src/main/store/setting.ts | 86 +++++++++++++++++++ pnpm-lock.yaml | 3 + 6 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 apps/agent-tars/src/main/store/setting.ts diff --git a/apps/agent-tars/package.json b/apps/agent-tars/package.json index 2a1dc7529..64437ff2b 100644 --- a/apps/agent-tars/package.json +++ b/apps/agent-tars/package.json @@ -80,6 +80,7 @@ "rimraf": "^6.0.1", "autoprefixer": "10.4.20", "electron": "34.1.1", + "electron-store": "^10.0.0", "electron-packager-languages": "0.6.0", "electron-vite": "^3.0.0", "jsdom": "^26.0.0", diff --git a/apps/agent-tars/src/main/customTools/search.ts b/apps/agent-tars/src/main/customTools/search.ts index c58d68580..6d8bced71 100644 --- a/apps/agent-tars/src/main/customTools/search.ts +++ b/apps/agent-tars/src/main/customTools/search.ts @@ -1,20 +1,16 @@ -import { SearchProvider, SearchSettings, ToolCall } from '@agent-infra/shared'; +import { SearchProvider, ToolCall } from '@agent-infra/shared'; import { SearchClient, SearchProvider as SearchProviderEnum, } from '@agent-infra/search'; import { MCPToolResult } from '@main/type'; import { tavily as tavilyCore } from '@tavily/core'; +import { SettingStore } from '@main/store/setting'; export const tavily = tavilyCore; -let currentSearchConfig: SearchSettings | null = null; - -export function updateSearchConfig(config: SearchSettings) { - currentSearchConfig = config; -} - const searchByTavily = async (options: { count: number; query: string }) => { + const currentSearchConfig = SettingStore.get('searchConfig'); const client = tavily({ apiKey: process.env.TAVILY_API_KEY || currentSearchConfig?.apiKey, }); @@ -33,6 +29,7 @@ const searchByTavily = async (options: { count: number; query: string }) => { }; export async function search(toolCall: ToolCall): Promise { + const currentSearchConfig = SettingStore.get('searchConfig'); const args = JSON.parse(toolCall.function.arguments); try { diff --git a/apps/agent-tars/src/main/ipcRoutes/llm.ts b/apps/agent-tars/src/main/ipcRoutes/llm.ts index 8f88c5479..12c40fcc7 100644 --- a/apps/agent-tars/src/main/ipcRoutes/llm.ts +++ b/apps/agent-tars/src/main/ipcRoutes/llm.ts @@ -4,13 +4,14 @@ import { ChatCompletionTool } from 'openai/resources/index.mjs'; import { BrowserWindow } from 'electron'; import { createLLM, LLMConfig } from '@main/llmProvider'; import { ProviderFactory } from '@main/llmProvider/ProviderFactory'; +import { SettingStore } from '@main/store/setting'; const t = initIpc.create(); const currentLLMConfigRef: { current: LLMConfig; } = { - current: {}, + current: SettingStore.get('llmConfig') || {}, }; export const llmRoute = t.router({ @@ -41,6 +42,7 @@ export const llmRoute = t.router({ const messages = input.messages.map((msg) => new Message(msg)); const llm = createLLM(currentLLMConfigRef.current); console.log('current llm config', currentLLMConfigRef.current); + console.log('input.tools', input.tools); const response = await llm.askTool({ messages, tools: input.tools, @@ -90,9 +92,14 @@ export const llmRoute = t.router({ return requestId; }), + getLLMConfig: t.procedure.input().handle(async () => { + return SettingStore.get('llmConfig'); + }), + updateLLMConfig: t.procedure.input().handle(async ({ input }) => { try { console.log('input entered', input); + SettingStore.set('llmConfig', input); currentLLMConfigRef.current = input; return true; } catch (error) { diff --git a/apps/agent-tars/src/main/ipcRoutes/search.ts b/apps/agent-tars/src/main/ipcRoutes/search.ts index 2d07f5663..4809bf973 100644 --- a/apps/agent-tars/src/main/ipcRoutes/search.ts +++ b/apps/agent-tars/src/main/ipcRoutes/search.ts @@ -1,6 +1,6 @@ import { initIpc } from '@ui-tars/electron-ipc/main'; -import { updateSearchConfig } from '../customTools/search'; import { SearchSettings } from '@agent-infra/shared'; +import { SettingStore } from '@main/store/setting'; const t = initIpc.create(); @@ -9,11 +9,15 @@ export const searchRoute = t.router({ .input() .handle(async ({ input }) => { try { - await updateSearchConfig(input); + SettingStore.set('searchConfig', input); return true; } catch (error) { console.error('Failed to update search configuration:', error); return false; } }), + + getSearchConfig: t.procedure.input().handle(async () => { + return SettingStore.get('searchConfig'); + }), }); diff --git a/apps/agent-tars/src/main/store/setting.ts b/apps/agent-tars/src/main/store/setting.ts new file mode 100644 index 000000000..e19541d7a --- /dev/null +++ b/apps/agent-tars/src/main/store/setting.ts @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2025 Bytedance, Inc. and its affiliates. + * SPDX-License-Identifier: Apache-2.0 + */ +import { BrowserWindow } from 'electron'; +import ElectronStore from 'electron-store'; +import { + ModelProvider, + SearchProvider, + SearchSettings, +} from '@agent-infra/shared'; +import { LLMConfig } from '@main/llmProvider/interfaces/LLMProvider'; + +export interface Settings { + llmConfig: LLMConfig; + searchConfig: SearchSettings; +} + +export const DEFAULT_SETTING: Settings = { + llmConfig: { + configName: ModelProvider.OPENAI, + model: 'gpt-4o', + apiKey: '', + apiVersion: '', + baseURL: '', + }, + searchConfig: { + provider: SearchProvider.DUCKDUCKGO_SEARCH, + apiKey: '', + }, +}; + +export class SettingStore { + private static instance: ElectronStore; + + public static getInstance(): ElectronStore { + if (!SettingStore.instance) { + SettingStore.instance = new ElectronStore({ + name: 'agent_tars.setting', + defaults: DEFAULT_SETTING, + }); + + SettingStore.instance.onDidAnyChange((newValue, oldValue) => { + console.log( + `SettingStore: ${JSON.stringify(oldValue)} changed to ${JSON.stringify(newValue)}`, + ); + // Notify that value updated + BrowserWindow.getAllWindows().forEach((win) => { + win.webContents.send('setting-updated', newValue); + }); + }); + } + return SettingStore.instance; + } + + public static set( + key: K, + value: Settings[K], + ): void { + SettingStore.getInstance().set(key, value); + } + + public static setStore(state: Settings): void { + SettingStore.getInstance().set(state); + } + + public static get(key: K): Settings[K] { + return SettingStore.getInstance().get(key); + } + + public static remove(key: K): void { + SettingStore.getInstance().delete(key); + } + + public static getStore(): Settings { + return SettingStore.getInstance().store; + } + + public static clear(): void { + SettingStore.getInstance().set(DEFAULT_SETTING); + } + + public static openInEditor(): void { + SettingStore.getInstance().openInEditor(); + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 845259f2c..db0e2b07f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -204,6 +204,9 @@ importers: electron-packager-languages: specifier: 0.6.0 version: 0.6.0 + electron-store: + specifier: ^10.0.0 + version: 10.0.1 electron-vite: specifier: ^3.0.0 version: 3.0.0(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(sass-embedded@1.83.4)(sass@1.85.1)(tsx@4.19.3)(yaml@2.7.0)) From 99bfc47882946ff6e67f12e851420626f8ed2bce Mon Sep 17 00:00:00 2001 From: ycjcl868 Date: Thu, 20 Mar 2025 15:03:54 +0800 Subject: [PATCH 2/3] fix: app settings --- .../agent-tars/src/main/customTools/search.ts | 4 +- apps/agent-tars/src/main/ipcRoutes/action.ts | 1 + apps/agent-tars/src/main/ipcRoutes/llm.ts | 48 ++++++++++----- apps/agent-tars/src/main/ipcRoutes/search.ts | 4 +- apps/agent-tars/src/main/store/setting.ts | 58 ++++++++++--------- .../src/renderer/src/api/llmConfig.ts | 4 +- .../src/renderer/src/services/llmSettings.ts | 14 ----- 7 files changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/agent-tars/src/main/customTools/search.ts b/apps/agent-tars/src/main/customTools/search.ts index 6d8bced71..0853de2d6 100644 --- a/apps/agent-tars/src/main/customTools/search.ts +++ b/apps/agent-tars/src/main/customTools/search.ts @@ -10,7 +10,7 @@ import { SettingStore } from '@main/store/setting'; export const tavily = tavilyCore; const searchByTavily = async (options: { count: number; query: string }) => { - const currentSearchConfig = SettingStore.get('searchConfig'); + const currentSearchConfig = SettingStore.get('search'); const client = tavily({ apiKey: process.env.TAVILY_API_KEY || currentSearchConfig?.apiKey, }); @@ -29,7 +29,7 @@ const searchByTavily = async (options: { count: number; query: string }) => { }; export async function search(toolCall: ToolCall): Promise { - const currentSearchConfig = SettingStore.get('searchConfig'); + const currentSearchConfig = SettingStore.get('search'); const args = JSON.parse(toolCall.function.arguments); try { diff --git a/apps/agent-tars/src/main/ipcRoutes/action.ts b/apps/agent-tars/src/main/ipcRoutes/action.ts index 0724973b6..a3a89f5ca 100644 --- a/apps/agent-tars/src/main/ipcRoutes/action.ts +++ b/apps/agent-tars/src/main/ipcRoutes/action.ts @@ -43,6 +43,7 @@ export const actionRoute = t.router({ listTools: t.procedure.handle(async () => { const mcpClient = await createMcpClient(); const tools = mcpToolsToAzureTools(await mcpClient.listTools()); + console.log('toolstools', tools); const customTools = listCustomTools(); return [ ...tools.map((tool) => tool.function), diff --git a/apps/agent-tars/src/main/ipcRoutes/llm.ts b/apps/agent-tars/src/main/ipcRoutes/llm.ts index 12c40fcc7..21e2026bb 100644 --- a/apps/agent-tars/src/main/ipcRoutes/llm.ts +++ b/apps/agent-tars/src/main/ipcRoutes/llm.ts @@ -1,4 +1,9 @@ -import { MCPServerName, Message, MessageData } from '@agent-infra/shared'; +import { + MCPServerName, + Message, + MessageData, + ModelSettings, +} from '@agent-infra/shared'; import { initIpc } from '@ui-tars/electron-ipc/main'; import { ChatCompletionTool } from 'openai/resources/index.mjs'; import { BrowserWindow } from 'electron'; @@ -8,10 +13,24 @@ import { SettingStore } from '@main/store/setting'; const t = initIpc.create(); +/** + * Get the current provider configuration based on settings + */ +function getLLMProviderConfig(settings: ModelSettings): LLMConfig { + const { provider, model, apiKey, apiVersion, endpoint } = settings; + return { + configName: provider, + model, + apiKey, + apiVersion, + baseURL: endpoint, + }; +} + const currentLLMConfigRef: { current: LLMConfig; } = { - current: SettingStore.get('llmConfig') || {}, + current: getLLMProviderConfig(SettingStore.get('model') || {}), }; export const llmRoute = t.router({ @@ -93,20 +112,21 @@ export const llmRoute = t.router({ }), getLLMConfig: t.procedure.input().handle(async () => { - return SettingStore.get('llmConfig'); + return SettingStore.get('model'); }), - updateLLMConfig: t.procedure.input().handle(async ({ input }) => { - try { - console.log('input entered', input); - SettingStore.set('llmConfig', input); - currentLLMConfigRef.current = input; - return true; - } catch (error) { - console.error('Failed to update LLM configuration:', error); - return false; - } - }), + updateLLMConfig: t.procedure + .input() + .handle(async ({ input }) => { + try { + SettingStore.set('model', input); + currentLLMConfigRef.current = getLLMProviderConfig(input); + return true; + } catch (error) { + console.error('Failed to update LLM configuration:', error); + return false; + } + }), getAvailableProviders: t.procedure.input().handle(async () => { try { diff --git a/apps/agent-tars/src/main/ipcRoutes/search.ts b/apps/agent-tars/src/main/ipcRoutes/search.ts index 4809bf973..60cfe572a 100644 --- a/apps/agent-tars/src/main/ipcRoutes/search.ts +++ b/apps/agent-tars/src/main/ipcRoutes/search.ts @@ -9,7 +9,7 @@ export const searchRoute = t.router({ .input() .handle(async ({ input }) => { try { - SettingStore.set('searchConfig', input); + SettingStore.set('search', input); return true; } catch (error) { console.error('Failed to update search configuration:', error); @@ -18,6 +18,6 @@ export const searchRoute = t.router({ }), getSearchConfig: t.procedure.input().handle(async () => { - return SettingStore.get('searchConfig'); + return SettingStore.get('search'); }), }); diff --git a/apps/agent-tars/src/main/store/setting.ts b/apps/agent-tars/src/main/store/setting.ts index e19541d7a..3760839aa 100644 --- a/apps/agent-tars/src/main/store/setting.ts +++ b/apps/agent-tars/src/main/store/setting.ts @@ -6,36 +6,42 @@ import { BrowserWindow } from 'electron'; import ElectronStore from 'electron-store'; import { ModelProvider, + ModelSettings, SearchProvider, SearchSettings, + FileSystemSettings, + AppSettings, } from '@agent-infra/shared'; -import { LLMConfig } from '@main/llmProvider/interfaces/LLMProvider'; -export interface Settings { - llmConfig: LLMConfig; - searchConfig: SearchSettings; -} +const DEFAULT_MODEL_SETTINGS: ModelSettings = { + provider: ModelProvider.OPENAI, + model: 'gpt-4o', + apiKey: '', + apiVersion: '', + endpoint: '', +}; + +const DEFAULT_FILESYSTEM_SETTINGS: FileSystemSettings = { + availableDirectories: [], +}; + +const DEFAULT_SEARCH_SETTINGS: SearchSettings = { + provider: SearchProvider.DUCKDUCKGO_SEARCH, + apiKey: '', +}; -export const DEFAULT_SETTING: Settings = { - llmConfig: { - configName: ModelProvider.OPENAI, - model: 'gpt-4o', - apiKey: '', - apiVersion: '', - baseURL: '', - }, - searchConfig: { - provider: SearchProvider.DUCKDUCKGO_SEARCH, - apiKey: '', - }, +export const DEFAULT_SETTING: AppSettings = { + model: DEFAULT_MODEL_SETTINGS, + fileSystem: DEFAULT_FILESYSTEM_SETTINGS, + search: DEFAULT_SEARCH_SETTINGS, }; export class SettingStore { - private static instance: ElectronStore; + private static instance: ElectronStore; - public static getInstance(): ElectronStore { + public static getInstance(): ElectronStore { if (!SettingStore.instance) { - SettingStore.instance = new ElectronStore({ + SettingStore.instance = new ElectronStore({ name: 'agent_tars.setting', defaults: DEFAULT_SETTING, }); @@ -53,26 +59,26 @@ export class SettingStore { return SettingStore.instance; } - public static set( + public static set( key: K, - value: Settings[K], + value: AppSettings[K], ): void { SettingStore.getInstance().set(key, value); } - public static setStore(state: Settings): void { + public static setStore(state: AppSettings): void { SettingStore.getInstance().set(state); } - public static get(key: K): Settings[K] { + public static get(key: K): AppSettings[K] { return SettingStore.getInstance().get(key); } - public static remove(key: K): void { + public static remove(key: K): void { SettingStore.getInstance().delete(key); } - public static getStore(): Settings { + public static getStore(): AppSettings { return SettingStore.getInstance().store; } diff --git a/apps/agent-tars/src/renderer/src/api/llmConfig.ts b/apps/agent-tars/src/renderer/src/api/llmConfig.ts index 343c228c7..57328bb84 100644 --- a/apps/agent-tars/src/renderer/src/api/llmConfig.ts +++ b/apps/agent-tars/src/renderer/src/api/llmConfig.ts @@ -1,6 +1,5 @@ import { ipcClient } from './index'; import { ModelSettings } from '@agent-infra/shared'; -import { getLLMProviderConfig } from '../services/llmSettings'; /** * Update the LLM configuration in the main process @@ -9,8 +8,7 @@ export async function updateLLMConfig( settings: ModelSettings, ): Promise { try { - const config = getLLMProviderConfig(settings); - return await ipcClient.updateLLMConfig(config); + return await ipcClient.updateLLMConfig(settings); } catch (error) { console.error('Failed to update LLM configuration:', error); return false; diff --git a/apps/agent-tars/src/renderer/src/services/llmSettings.ts b/apps/agent-tars/src/renderer/src/services/llmSettings.ts index e559eebdc..fa57a7b2d 100644 --- a/apps/agent-tars/src/renderer/src/services/llmSettings.ts +++ b/apps/agent-tars/src/renderer/src/services/llmSettings.ts @@ -27,17 +27,3 @@ export function saveLLMSettings(settings: ModelSettings): void { console.error('Failed to save LLM settings', e); } } - -/** - * Get the current provider configuration based on settings - */ -export function getLLMProviderConfig(settings: ModelSettings) { - const { provider, model, apiKey, apiVersion, endpoint } = settings; - return { - configName: provider, - model, - apiKey, - apiVersion, - baseURL: endpoint, - }; -} From 372590591146ec8eeddca1bb6da757b21f15ca58 Mon Sep 17 00:00:00 2001 From: ycjcl868 Date: Thu, 20 Mar 2025 15:23:53 +0800 Subject: [PATCH 3/3] feat: settings support electron-store --- apps/agent-tars/src/main/ipcRoutes/index.ts | 3 +- apps/agent-tars/src/main/ipcRoutes/llm.ts | 1 + .../agent-tars/src/main/ipcRoutes/settings.ts | 26 +++++++++++ .../src/renderer/src/agent/AgentFlow.ts | 18 -------- .../renderer/src/api/fileSystemInterceptor.ts | 14 +++--- .../components/FilePermissionModal/index.tsx | 9 ++-- .../LeftSidebar/Settings/useAppSettings.ts | 43 ++++++------------- .../LeftSidebar/Settings/useModelSettings.ts | 17 +++----- .../src/hooks/useFileSystemSettings.ts | 15 +++---- .../src/services/filePermissionService.ts | 8 ++-- .../src/services/fileSystemSettings.ts | 31 +++---------- .../src/renderer/src/services/llmSettings.ts | 29 ------------- .../renderer/src/services/searchSettings.ts | 22 ---------- 13 files changed, 75 insertions(+), 161 deletions(-) create mode 100644 apps/agent-tars/src/main/ipcRoutes/settings.ts delete mode 100644 apps/agent-tars/src/renderer/src/services/llmSettings.ts delete mode 100644 apps/agent-tars/src/renderer/src/services/searchSettings.ts diff --git a/apps/agent-tars/src/main/ipcRoutes/index.ts b/apps/agent-tars/src/main/ipcRoutes/index.ts index 87ea18a34..d990bf9a0 100644 --- a/apps/agent-tars/src/main/ipcRoutes/index.ts +++ b/apps/agent-tars/src/main/ipcRoutes/index.ts @@ -5,7 +5,7 @@ import { actionRoute } from './action'; import { browserRoute } from './browser'; import { fileSystemRoute } from './filesystem'; import { searchRoute } from './search'; - +import { settingsRoute } from './settings'; const t = initIpc.create(); export const ipcRoutes = t.router({ @@ -15,6 +15,7 @@ export const ipcRoutes = t.router({ ...browserRoute, ...fileSystemRoute, ...searchRoute, + ...settingsRoute, }); export type Router = typeof ipcRoutes; diff --git a/apps/agent-tars/src/main/ipcRoutes/llm.ts b/apps/agent-tars/src/main/ipcRoutes/llm.ts index 21e2026bb..b645924d0 100644 --- a/apps/agent-tars/src/main/ipcRoutes/llm.ts +++ b/apps/agent-tars/src/main/ipcRoutes/llm.ts @@ -23,6 +23,7 @@ function getLLMProviderConfig(settings: ModelSettings): LLMConfig { model, apiKey, apiVersion, + // TODO: baseURL || endpoint baseURL: endpoint, }; } diff --git a/apps/agent-tars/src/main/ipcRoutes/settings.ts b/apps/agent-tars/src/main/ipcRoutes/settings.ts new file mode 100644 index 000000000..bcc09942d --- /dev/null +++ b/apps/agent-tars/src/main/ipcRoutes/settings.ts @@ -0,0 +1,26 @@ +import { AppSettings } from '@agent-infra/shared'; +import { SettingStore } from '@main/store/setting'; +import { initIpc } from '@ui-tars/electron-ipc/main'; + +const t = initIpc.create(); + +export const settingsRoute = t.router({ + getSettings: t.procedure.input().handle(async () => { + return SettingStore.getStore(); + }), + getFileSystemSettings: t.procedure.input().handle(async () => { + return SettingStore.get('fileSystem'); + }), + updateAppSettings: t.procedure + .input() + .handle(async ({ input }) => { + SettingStore.setStore(input); + return true; + }), + updateFileSystemSettings: t.procedure + .input() + .handle(async ({ input }) => { + SettingStore.set('fileSystem', input); + return true; + }), +}); diff --git a/apps/agent-tars/src/renderer/src/agent/AgentFlow.ts b/apps/agent-tars/src/renderer/src/agent/AgentFlow.ts index 2ab5df01e..b072b6c72 100644 --- a/apps/agent-tars/src/renderer/src/agent/AgentFlow.ts +++ b/apps/agent-tars/src/renderer/src/agent/AgentFlow.ts @@ -17,7 +17,6 @@ import { Greeter } from './Greeter'; import { extractHistoryEvents } from '@renderer/utils/extractHistoryEvents'; import { EventItem, EventType } from '@renderer/type/event'; import { SNAPSHOT_BROWSER_ACTIONS } from '@renderer/constants'; -import { loadLLMSettings } from '@renderer/services/llmSettings'; export interface AgentContext { plan: PlanTask[]; @@ -40,23 +39,6 @@ export class AgentFlow { private loadingStatusTip = ''; constructor(private appContext: AppContext) { - // Load LLM settings and update the configuration - const llmSettings = loadLLMSettings(); - if (llmSettings) { - // Update LLM configuration when starting the agent flow - ipcClient - .updateLLMConfig({ - configName: llmSettings.provider, - model: llmSettings.model, - apiKey: llmSettings.apiKey, - apiVersion: llmSettings.apiVersion, - baseURL: llmSettings.endpoint, - }) - .catch((error) => { - console.error('Failed to update LLM configuration:', error); - }); - } - const omegaHistoryEvents = this.parseHistoryEvents(); this.eventManager = new EventManager(omegaHistoryEvents); this.abortController = new AbortController(); diff --git a/apps/agent-tars/src/renderer/src/api/fileSystemInterceptor.ts b/apps/agent-tars/src/renderer/src/api/fileSystemInterceptor.ts index be4cc1d58..bc48dc511 100644 --- a/apps/agent-tars/src/renderer/src/api/fileSystemInterceptor.ts +++ b/apps/agent-tars/src/renderer/src/api/fileSystemInterceptor.ts @@ -87,14 +87,18 @@ export async function interceptToolCalls( toolName === ToolCallType.DirectoryTree || toolName === ToolCallType.GetFileInfo ) { - updatedParams.path = normalizePath(params.path); + updatedParams.path = await normalizePath(params.path); } else if (toolName === ToolCallType.ReadMultipleFiles) { - updatedParams.paths = (params.paths || []).map(normalizePath); + updatedParams.paths = await Promise.all( + (params.paths || []).map((path: string) => { + return normalizePath(path); + }), + ); } else if (toolName === ToolCallType.MoveFile) { - updatedParams.source = normalizePath(params.source); - updatedParams.destination = normalizePath(params.destination); + updatedParams.source = await normalizePath(params.source); + updatedParams.destination = await normalizePath(params.destination); } else if (toolName === ToolCallType.SearchFiles) { - updatedParams.path = normalizePath(params.path); + updatedParams.path = await normalizePath(params.path); } // Update the tool call with normalized paths diff --git a/apps/agent-tars/src/renderer/src/components/FilePermissionModal/index.tsx b/apps/agent-tars/src/renderer/src/components/FilePermissionModal/index.tsx index f082c8aa9..eeba4d569 100644 --- a/apps/agent-tars/src/renderer/src/components/FilePermissionModal/index.tsx +++ b/apps/agent-tars/src/renderer/src/components/FilePermissionModal/index.tsx @@ -10,10 +10,6 @@ import { } from '@nextui-org/react'; import { IoWarningOutline } from 'react-icons/io5'; import { ipcClient } from '@renderer/api'; -import { - loadFileSystemSettings, - saveFileSystemSettings, -} from '@renderer/services/fileSystemSettings'; import path from 'path-browserify'; import { resolvePermission } from '@renderer/services/filePermissionService'; import { useAppSettings } from '../LeftSidebar/Settings/useAppSettings'; @@ -35,12 +31,13 @@ export function FilePermissionModal({ setIsProcessing(true); try { // Add this directory to allowed directories - const settings = loadFileSystemSettings() || { + const settings = (await ipcClient.getFileSystemSettings()) || { availableDirectories: [], }; + if (!settings.availableDirectories.includes(directoryPath)) { settings.availableDirectories.push(directoryPath); - saveFileSystemSettings(settings); + await ipcClient.updateFileSystemSettings(settings); setSettings((appSettings) => { return { ...appSettings, diff --git a/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useAppSettings.ts b/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useAppSettings.ts index 80bdb43a6..0e222dbe9 100644 --- a/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useAppSettings.ts +++ b/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useAppSettings.ts @@ -7,22 +7,9 @@ import { SearchSettings, SearchProvider, } from '@agent-infra/shared'; -import { - loadLLMSettings, - saveLLMSettings, -} from '../../../services/llmSettings'; -import { updateLLMConfig } from '../../../api/llmConfig'; -import { - loadFileSystemSettings, - saveFileSystemSettings, -} from '../../../services/fileSystemSettings'; import { ipcClient } from '@renderer/api'; import { atom, useAtom } from 'jotai'; import toast from 'react-hot-toast'; -import { - loadSearchSettings, - saveSearchSettings, -} from '../../../services/searchSettings'; const DEFAULT_MODEL_SETTINGS: ModelSettings = { provider: ModelProvider.OPENAI, @@ -50,17 +37,18 @@ export const appSettingsAtom = atom({ export function useAppSettings() { const [settings, setSettings] = useAtom(appSettingsAtom); - // Load settings from localStorage on mount + // Load settings from store on mount useEffect(() => { - const savedModelSettings = loadLLMSettings(); - const savedFileSystemSettings = loadFileSystemSettings(); - const savedSearchSettings = loadSearchSettings(); - - setSettings({ - model: savedModelSettings || DEFAULT_MODEL_SETTINGS, - fileSystem: savedFileSystemSettings || DEFAULT_FILESYSTEM_SETTINGS, - search: savedSearchSettings || DEFAULT_SEARCH_SETTINGS, - }); + async function loadSettings() { + const settings = await ipcClient.getSettings(); + + setSettings({ + model: settings.model || DEFAULT_MODEL_SETTINGS, + fileSystem: settings.fileSystem || DEFAULT_FILESYSTEM_SETTINGS, + search: settings.search || DEFAULT_SEARCH_SETTINGS, + }); + } + loadSettings(); }, []); const validateModelSettings = ( @@ -125,14 +113,7 @@ export function useAppSettings() { try { // Save all settings - saveLLMSettings(settings.model); - await updateLLMConfig(settings.model); - - saveFileSystemSettings(settings.fileSystem); - await ipcClient.updateFileSystemConfig(settings.fileSystem); - - saveSearchSettings(settings.search); - await ipcClient.updateSearchConfig(settings.search); + await ipcClient.updateAppSettings(settings); toast.success('Settings saved successfully'); return true; diff --git a/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useModelSettings.ts b/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useModelSettings.ts index 5a0129058..853ebce0b 100644 --- a/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useModelSettings.ts +++ b/apps/agent-tars/src/renderer/src/components/LeftSidebar/Settings/useModelSettings.ts @@ -1,10 +1,7 @@ import { useState, useEffect } from 'react'; -import { - loadLLMSettings, - saveLLMSettings, -} from '../../../services/llmSettings'; import { updateLLMConfig } from '../../../api/llmConfig'; import { ModelProvider, ModelSettings } from '@agent-infra/shared'; +import { ipcClient } from '@renderer/api'; export function useModelSettings() { const [settings, setSettings] = useState({ @@ -15,21 +12,19 @@ export function useModelSettings() { endpoint: '', }); - // Load settings from localStorage on mount + // Load settings from store on mount useEffect(() => { - const savedSettings = loadLLMSettings(); - if (savedSettings) { - setSettings(savedSettings); + async function loadSettings() { + const settings = await ipcClient.getSettings(); + setSettings(settings.model); } + loadSettings(); }, []); const saveSettings = async () => { // Save settings directly without modifying the model field const finalSettings = { ...settings }; - // Save to localStorage - saveLLMSettings(finalSettings); - // Update LLM configuration in main process await updateLLMConfig(finalSettings); }; diff --git a/apps/agent-tars/src/renderer/src/hooks/useFileSystemSettings.ts b/apps/agent-tars/src/renderer/src/hooks/useFileSystemSettings.ts index 84c884708..75de3a2bb 100644 --- a/apps/agent-tars/src/renderer/src/hooks/useFileSystemSettings.ts +++ b/apps/agent-tars/src/renderer/src/hooks/useFileSystemSettings.ts @@ -1,9 +1,5 @@ import { useEffect, useState } from 'react'; import { ipcClient } from '@renderer/api'; -import { - loadFileSystemSettings, - saveFileSystemSettings, -} from '@renderer/services/fileSystemSettings'; export function useFileSystemSettings() { const [initialized, setInitialized] = useState(false); @@ -14,12 +10,15 @@ export function useFileSystemSettings() { // Get current allowed directories from main process const allowedDirectories = await ipcClient.getAllowedDirectories(); - // Load settings from localStorage - const settings = loadFileSystemSettings(); + // Load settings from store + const appSettings = await ipcClient.getSettings(); + const settings = appSettings?.fileSystem; // If no settings exist, create them with the allowed directories if (!settings) { - saveFileSystemSettings({ availableDirectories: allowedDirectories }); + await ipcClient.updateFileSystemSettings({ + availableDirectories: allowedDirectories, + }); } else { // Make sure the settings match the main process const updatedSettings = { @@ -33,7 +32,7 @@ export function useFileSystemSettings() { }; // Save updated settings - saveFileSystemSettings(updatedSettings); + await ipcClient.updateFileSystemSettings(updatedSettings); // Update main process if needed if ( diff --git a/apps/agent-tars/src/renderer/src/services/filePermissionService.ts b/apps/agent-tars/src/renderer/src/services/filePermissionService.ts index a429cc26b..ff89c709d 100644 --- a/apps/agent-tars/src/renderer/src/services/filePermissionService.ts +++ b/apps/agent-tars/src/renderer/src/services/filePermissionService.ts @@ -18,14 +18,14 @@ export const pendingPermissionRequestAtom = atom( * @param filePath The file path to normalize * @returns Normalized path (absolute) */ -export function normalizePath(filePath: string): string { +export async function normalizePath(filePath: string): Promise { // If it's already an absolute path, return it if (filePath.startsWith('/')) { return filePath; } // Otherwise, make it relative to the default directory - const defaultDir = getDefaultDirectory(); + const defaultDir = await getDefaultDirectory(); if (!defaultDir) { throw new Error('No default directory configured'); } @@ -40,10 +40,10 @@ export function normalizePath(filePath: string): string { */ export async function checkPathPermission(filePath: string): Promise { // Normalize path first - const normalizedPath = normalizePath(filePath); + const normalizedPath = await normalizePath(filePath); // If path is allowed, return immediately - if (isPathAllowed(normalizedPath)) { + if (await isPathAllowed(normalizedPath)) { return true; } diff --git a/apps/agent-tars/src/renderer/src/services/fileSystemSettings.ts b/apps/agent-tars/src/renderer/src/services/fileSystemSettings.ts index 7e2822d12..579a2b36f 100644 --- a/apps/agent-tars/src/renderer/src/services/fileSystemSettings.ts +++ b/apps/agent-tars/src/renderer/src/services/fileSystemSettings.ts @@ -1,36 +1,15 @@ -import { FileSystemSettings } from '@agent-infra/shared'; +import { ipcClient } from '@renderer/api'; -const FILE_SYSTEM_SETTINGS_KEY = 'omega-filesystem-settings'; - -export function loadFileSystemSettings(): FileSystemSettings | null { - try { - const settingsJson = localStorage.getItem(FILE_SYSTEM_SETTINGS_KEY); - if (!settingsJson) return null; - return JSON.parse(settingsJson) as FileSystemSettings; - } catch (error) { - console.error('Failed to load file system settings:', error); - return null; - } -} - -export function saveFileSystemSettings(settings: FileSystemSettings): void { - try { - localStorage.setItem(FILE_SYSTEM_SETTINGS_KEY, JSON.stringify(settings)); - } catch (error) { - console.error('Failed to save file system settings:', error); - } -} - -export function getDefaultDirectory(): string | null { - const settings = loadFileSystemSettings(); +export async function getDefaultDirectory(): Promise { + const settings = await ipcClient.getFileSystemSettings(); if (settings && settings.availableDirectories.length > 0) { return settings.availableDirectories[0]; } return null; } -export function isPathAllowed(path: string): boolean { - const settings = loadFileSystemSettings(); +export async function isPathAllowed(path: string): Promise { + const settings = await ipcClient.getFileSystemSettings(); if (!settings || !settings.availableDirectories.length) return false; // If path is not absolute, it's allowed (will be relative to default dir) diff --git a/apps/agent-tars/src/renderer/src/services/llmSettings.ts b/apps/agent-tars/src/renderer/src/services/llmSettings.ts deleted file mode 100644 index fa57a7b2d..000000000 --- a/apps/agent-tars/src/renderer/src/services/llmSettings.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ModelSettings } from '@agent-infra/shared'; - -const STORAGE_KEY = 'ai-model-settings'; - -/** - * Load LLM settings from localStorage - */ -export function loadLLMSettings(): ModelSettings | null { - try { - const savedSettings = localStorage.getItem(STORAGE_KEY); - if (savedSettings) { - return JSON.parse(savedSettings); - } - } catch (e) { - console.error('Failed to parse saved LLM settings', e); - } - return null; -} - -/** - * Save LLM settings to localStorage - */ -export function saveLLMSettings(settings: ModelSettings): void { - try { - localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); - } catch (e) { - console.error('Failed to save LLM settings', e); - } -} diff --git a/apps/agent-tars/src/renderer/src/services/searchSettings.ts b/apps/agent-tars/src/renderer/src/services/searchSettings.ts deleted file mode 100644 index 9008c4ba0..000000000 --- a/apps/agent-tars/src/renderer/src/services/searchSettings.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { SearchSettings } from '@agent-infra/shared'; - -const SEARCH_SETTINGS_KEY = 'omega-search-settings'; - -export function loadSearchSettings(): SearchSettings | null { - try { - const settingsJson = localStorage.getItem(SEARCH_SETTINGS_KEY); - if (!settingsJson) return null; - return JSON.parse(settingsJson) as SearchSettings; - } catch (error) { - console.error('Failed to load search settings:', error); - return null; - } -} - -export function saveSearchSettings(settings: SearchSettings): void { - try { - localStorage.setItem(SEARCH_SETTINGS_KEY, JSON.stringify(settings)); - } catch (error) { - console.error('Failed to save search settings:', error); - } -}