diff --git a/CLAUDE.md b/CLAUDE.md index 3a47b0de5f..f1a2f2a48a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,13 +21,18 @@ This file provides guidance to AI coding assistants when working with code in th ## Development Commands -- **Install**: `yarn install` -- **Development**: `yarn dev` - Runs Electron app in development mode -- **Debug**: `yarn debug` - Starts with debugging enabled, use chrome://inspect -- **Build Check**: `yarn build:check` - REQUIRED before commits (lint + test + typecheck) -- **Test**: `yarn test` - Run all tests (Vitest) -- **Single Test**: `yarn test:main` or `yarn test:renderer` -- **Lint**: `yarn lint` - Fix linting issues and run typecheck +- **Install**: `yarn install` - Install all project dependencies +- **Development**: `yarn dev` - Runs Electron app in development mode with hot reload +- **Debug**: `yarn debug` - Starts with debugging enabled, use `chrome://inspect` to attach debugger +- **Build Check**: `yarn build:check` - **REQUIRED** before commits (lint + test + typecheck) + - If having i18n sort issues, run `yarn i18n:sync` first to sync template + - If having formatting issues, run `yarn format` first +- **Test**: `yarn test` - Run all tests (Vitest) across main and renderer processes +- **Single Test**: + - `yarn test:main` - Run tests for main process only + - `yarn test:renderer` - Run tests for renderer process only +- **Lint**: `yarn lint` - Fix linting issues and run TypeScript type checking +- **Format**: `yarn format` - Auto-format code using Biome ## Project Architecture diff --git a/package.json b/package.json index 8be83e9e37..18408e4a74 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "test:e2e": "yarn playwright test", "test:lint": "oxlint --deny-warnings && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --cache", "test:scripts": "vitest scripts", - "lint": "oxlint --fix && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --cache && yarn typecheck && yarn check:i18n", + "lint": "oxlint --fix && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --cache && yarn typecheck && yarn check:i18n && yarn format:check", "format": "biome format --write && biome lint --write", "format:check": "biome format && biome lint", "prepare": "git config blame.ignoreRevsFile .git-blame-ignore-revs && husky", diff --git a/src/main/apiServer/services/mcp.ts b/src/main/apiServer/services/mcp.ts index d6acae745e..4cb19477b8 100644 --- a/src/main/apiServer/services/mcp.ts +++ b/src/main/apiServer/services/mcp.ts @@ -113,14 +113,14 @@ class MCPApiService extends EventEmitter { const client = await mcpService.initClient(server) const tools = await client.listTools() - logger.info(`Server with id ${id} info:`, { tools: JSON.stringify(tools) }) + logger.silly(`Server with id ${id} info:`, { tools: JSON.stringify(tools.tools) }) return { id: server.id, name: server.name, type: server.type, description: server.description, - tools + tools: tools.tools } } catch (error: any) { logger.error(`Failed to get server info with id ${id}:`, error) diff --git a/src/renderer/src/components/ApiModelLabel.tsx b/src/renderer/src/components/ApiModelLabel.tsx index e9c78deb48..4e6d318ebd 100644 --- a/src/renderer/src/components/ApiModelLabel.tsx +++ b/src/renderer/src/components/ApiModelLabel.tsx @@ -5,15 +5,22 @@ import React from 'react' export interface ModelLabelProps extends Omit, 'children'> { model?: ApiModel + classNames?: { + container?: string + avatar?: string + modelName?: string + divider?: string + providerName?: string + } } -export const ApiModelLabel: React.FC = ({ model, className, ...props }) => { +export const ApiModelLabel: React.FC = ({ model, className, classNames, ...props }) => { return ( -
- - - {model?.name} | {model?.provider_name} - +
+ + {model?.name} + | + {model?.provider_name}
) } diff --git a/src/renderer/src/components/Popups/agent/AgentModal.tsx b/src/renderer/src/components/Popups/agent/AgentModal.tsx index 6536c6103e..ebce1b05d2 100644 --- a/src/renderer/src/components/Popups/agent/AgentModal.tsx +++ b/src/renderer/src/components/Popups/agent/AgentModal.tsx @@ -25,6 +25,7 @@ import { useApiModels } from '@renderer/hooks/agents/useModels' import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent' import { AddAgentForm, + AgentConfigurationSchema, AgentEntity, AgentType, BaseAgentForm, @@ -57,7 +58,9 @@ const buildAgentForm = (existing?: AgentWithTools): BaseAgentForm => ({ instructions: existing?.instructions, model: existing?.model ?? 'claude-4-sonnet', accessible_paths: existing?.accessible_paths ? [...existing.accessible_paths] : [], - allowed_tools: existing?.allowed_tools ? [...existing.allowed_tools] : [] + allowed_tools: existing?.allowed_tools ? [...existing.allowed_tools] : [], + mcps: existing?.mcps ? [...existing.mcps] : [], + configuration: AgentConfigurationSchema.parse(existing?.configuration ?? {}) }) interface BaseProps { @@ -320,7 +323,8 @@ export const AgentModal: React.FC = ({ agent, trigger, isOpen: _isOpen, o instructions: form.instructions, model: form.model, accessible_paths: [...form.accessible_paths], - allowed_tools: [...form.allowed_tools] + allowed_tools: [...form.allowed_tools], + configuration: form.configuration ? { ...form.configuration } : undefined } satisfies UpdateAgentForm updateAgent(updatePayload) @@ -333,7 +337,8 @@ export const AgentModal: React.FC = ({ agent, trigger, isOpen: _isOpen, o instructions: form.instructions, model: form.model, accessible_paths: [...form.accessible_paths], - allowed_tools: [...form.allowed_tools] + allowed_tools: [...form.allowed_tools], + configuration: form.configuration ? { ...form.configuration } : undefined } satisfies AddAgentForm addAgent(newAgent) logger.debug('Added agent', newAgent) @@ -352,6 +357,7 @@ export const AgentModal: React.FC = ({ agent, trigger, isOpen: _isOpen, o form.instructions, form.accessible_paths, form.allowed_tools, + form.configuration, agent, onClose, t, diff --git a/src/renderer/src/components/Popups/agent/SessionModal.tsx b/src/renderer/src/components/Popups/agent/SessionModal.tsx index 98906f52b1..efa037a72e 100644 --- a/src/renderer/src/components/Popups/agent/SessionModal.tsx +++ b/src/renderer/src/components/Popups/agent/SessionModal.tsx @@ -1,6 +1,5 @@ import { Button, - Chip, cn, Form, Input, @@ -18,6 +17,7 @@ import { } from '@heroui/react' import { loggerService } from '@logger' import type { Selection } from '@react-types/shared' +import { AllowedToolsSelect } from '@renderer/components/agent' import { getModelLogo } from '@renderer/config/models' import { useAgent } from '@renderer/hooks/agents/useAgent' import { useApiModels } from '@renderer/hooks/agents/useModels' @@ -58,7 +58,8 @@ const buildSessionForm = (existing?: SessionWithTools, agent?: AgentWithTools): ? [...existing.allowed_tools] : agent?.allowed_tools ? [...agent.allowed_tools] - : [] + : [], + mcps: existing?.mcps ? [...existing.mcps] : agent?.mcps ? [...agent.mcps] : [] }) interface BaseProps { @@ -197,21 +198,6 @@ export const SessionModal: React.FC = ({ [availableTools] ) - const renderSelectedTools = useCallback((items: SelectedItems) => { - if (!items.length) { - return null - } - return ( -
- {items.map((item) => ( - - {item.data?.name ?? item.textValue ?? item.key} - - ))} -
- ) - }, []) - const modelOptions = useMemo(() => { // mocked data. not final version return (models ?? []).map((model) => ({ @@ -266,7 +252,8 @@ export const SessionModal: React.FC = ({ instructions: form.instructions, model: form.model, accessible_paths: [...form.accessible_paths], - allowed_tools: [...(form.allowed_tools ?? [])] + allowed_tools: [...(form.allowed_tools ?? [])], + mcps: [...(form.mcps ?? [])] } satisfies UpdateSessionForm updateSession(updatePayload) @@ -278,7 +265,8 @@ export const SessionModal: React.FC = ({ instructions: form.instructions, model: form.model, accessible_paths: [...form.accessible_paths], - allowed_tools: [...(form.allowed_tools ?? [])] + allowed_tools: [...(form.allowed_tools ?? [])], + mcps: [...(form.mcps ?? [])] } satisfies CreateSessionForm const createdSession = await createSession(newSession) if (createdSession) { @@ -300,6 +288,7 @@ export const SessionModal: React.FC = ({ form.instructions, form.accessible_paths, form.allowed_tools, + form.mcps, session, onClose, onSessionCreated, @@ -359,31 +348,11 @@ export const SessionModal: React.FC = ({ value={form.description ?? ''} onValueChange={onDescChange} /> - + />