diff --git a/src/main/presenter/configPresenter/acpConfHelper.ts b/src/main/presenter/configPresenter/acpConfHelper.ts index 246bfb6c0..d30037f19 100644 --- a/src/main/presenter/configPresenter/acpConfHelper.ts +++ b/src/main/presenter/configPresenter/acpConfHelper.ts @@ -8,6 +8,7 @@ import type { AcpCustomAgent, AcpStoreData } from '@shared/presenter' +import { McpConfHelper } from './mcpConfHelper' const ACP_STORE_VERSION = '2' const DEFAULT_PROFILE_NAME = 'Default' @@ -64,8 +65,10 @@ const deepClone = (value: T): T => { export class AcpConfHelper { private store: ElectronStore + private readonly mcpConfHelper: McpConfHelper - constructor() { + constructor(options?: { mcpConfHelper?: McpConfHelper }) { + this.mcpConfHelper = options?.mcpConfHelper ?? new McpConfHelper() this.store = new ElectronStore({ name: 'acp_agents', defaults: { @@ -149,6 +152,57 @@ export class AcpConfHelper { return deepClone(this.getData().customs) } + async getAgentMcpSelections(agentId: string, isBuiltin?: boolean): Promise { + const builtin = typeof isBuiltin === 'boolean' ? isBuiltin : this.isBuiltinAgent(agentId) + if (builtin) { + const agent = this.getBuiltins().find((item) => item.id === agentId) + return this.normalizeMcpSelections(agent?.mcpSelections) ?? [] + } + + const agent = this.getCustoms().find((item) => item.id === agentId) + return this.normalizeMcpSelections(agent?.mcpSelections) ?? [] + } + + async setAgentMcpSelections( + agentId: string, + isBuiltin: boolean, + mcpIds: string[] + ): Promise { + const normalized = this.normalizeMcpSelections(mcpIds) ?? [] + const validated = await this.validateMcpSelections(normalized) + + if (isBuiltin) { + this.mutateBuiltins((builtins) => { + const target = builtins.find((agent) => agent.id === agentId) + if (!target) { + throw new Error(`ACP builtin agent not found: ${agentId}`) + } + target.mcpSelections = validated + }) + return + } + + this.mutateCustoms((customs) => { + const target = customs.find((agent) => agent.id === agentId) + if (!target) { + throw new Error(`ACP custom agent not found: ${agentId}`) + } + target.mcpSelections = validated + }) + } + + async addMcpToAgent(agentId: string, isBuiltin: boolean, mcpId: string): Promise { + const current = await this.getAgentMcpSelections(agentId, isBuiltin) + const next = Array.from(new Set([...current, mcpId])) + await this.setAgentMcpSelections(agentId, isBuiltin, next) + } + + async removeMcpFromAgent(agentId: string, isBuiltin: boolean, mcpId: string): Promise { + const current = await this.getAgentMcpSelections(agentId, isBuiltin) + const next = current.filter((id) => id !== mcpId) + await this.setAgentMcpSelections(agentId, isBuiltin, next) + } + addBuiltinProfile( agentId: AcpBuiltinAgentId, profile: Omit, @@ -585,7 +639,8 @@ export class AcpConfHelper { name: BUILTIN_TEMPLATES[id].name, enabled: false, activeProfileId: profile.id, - profiles: [profile] + profiles: [profile], + mcpSelections: undefined } } @@ -620,7 +675,8 @@ export class AcpConfHelper { name: template.name, enabled: Boolean(agent.enabled), activeProfileId, - profiles + profiles, + mcpSelections: this.normalizeMcpSelections(agent.mcpSelections) } } @@ -682,7 +738,8 @@ export class AcpConfHelper { command, args: this.normalizeArgs(agent.args), env: this.normalizeEnv(agent.env), - enabled + enabled, + mcpSelections: this.normalizeMcpSelections(agent.mcpSelections) } } @@ -722,6 +779,26 @@ export class AcpConfHelper { return Object.fromEntries(entries) } + private normalizeMcpSelections(value: unknown): string[] | undefined { + if (!Array.isArray(value)) return undefined + const cleaned = value + .map((item) => (typeof item === 'string' ? item.trim() : String(item).trim())) + .filter((item) => item.length > 0) + if (!cleaned.length) return undefined + return Array.from(new Set(cleaned)) + } + + private async validateMcpSelections(selections: string[]): Promise { + if (!selections.length) return [] + const servers = await this.mcpConfHelper.getMcpServers() + const valid = new Set( + Object.entries(servers) + .filter(([, config]) => config?.type !== 'inmemory') + .map(([name]) => name) + ) + return selections.filter((name) => valid.has(name)) + } + private isBuiltinAgent(id: string): id is AcpBuiltinAgentId { return BUILTIN_ORDER.includes(id as AcpBuiltinAgentId) } diff --git a/src/main/presenter/configPresenter/index.ts b/src/main/presenter/configPresenter/index.ts index 25b329a98..4e0c85780 100644 --- a/src/main/presenter/configPresenter/index.ts +++ b/src/main/presenter/configPresenter/index.ts @@ -190,13 +190,13 @@ export class ConfigPresenter implements IConfigPresenter { setSetting: this.setSetting.bind(this) }) - this.acpConfHelper = new AcpConfHelper() - this.syncAcpProviderEnabled(this.acpConfHelper.getGlobalEnabled()) - this.setupIpcHandlers() - // Initialize MCP configuration helper this.mcpConfHelper = new McpConfHelper() + this.acpConfHelper = new AcpConfHelper({ mcpConfHelper: this.mcpConfHelper }) + this.syncAcpProviderEnabled(this.acpConfHelper.getGlobalEnabled()) + this.setupIpcHandlers() + // Initialize model configuration helper this.modelConfigHelper = new ModelConfigHelper(this.currentAppVersion) @@ -1184,6 +1184,29 @@ export class ConfigPresenter implements IConfigPresenter { this.handleAcpAgentsMutated([agentId]) } + async getAgentMcpSelections(agentId: string, isBuiltin?: boolean): Promise { + return await this.acpConfHelper.getAgentMcpSelections(agentId, isBuiltin) + } + + async setAgentMcpSelections( + agentId: string, + isBuiltin: boolean, + mcpIds: string[] + ): Promise { + await this.acpConfHelper.setAgentMcpSelections(agentId, isBuiltin, mcpIds) + this.handleAcpAgentsMutated([agentId]) + } + + async addMcpToAgent(agentId: string, isBuiltin: boolean, mcpId: string): Promise { + await this.acpConfHelper.addMcpToAgent(agentId, isBuiltin, mcpId) + this.handleAcpAgentsMutated([agentId]) + } + + async removeMcpFromAgent(agentId: string, isBuiltin: boolean, mcpId: string): Promise { + await this.acpConfHelper.removeMcpFromAgent(agentId, isBuiltin, mcpId) + this.handleAcpAgentsMutated([agentId]) + } + private handleAcpAgentsMutated(agentIds?: string[]) { this.clearProviderModelStatusCache('acp') this.notifyAcpAgentsChanged() diff --git a/src/main/presenter/configPresenter/systemPromptHelper.ts b/src/main/presenter/configPresenter/systemPromptHelper.ts index 49f365b8d..18c2640f3 100644 --- a/src/main/presenter/configPresenter/systemPromptHelper.ts +++ b/src/main/presenter/configPresenter/systemPromptHelper.ts @@ -8,7 +8,7 @@ type SetSetting = (key: string, value: T) => void export const DEFAULT_SYSTEM_PROMPT = `You are DeepChat, a highly capable AI assistant. Your goal is to fully complete the user’s requested task before handing the conversation back to them. Keep working autonomously until the task is fully resolved. Be thorough in gathering information. Before replying, make sure you have all the details necessary to provide a complete solution. Use additional tools or ask clarifying questions when needed, but if you can find the answer on your own, avoid asking the user for help. When using tools, briefly describe your intended steps first—for example, which tool you’ll use and for what purpose. -Adhere to this in all languages.Always respond in the same language as the user's query.` +Adhere to this in all languages.Respond in the same language as the user's query.` type GetSetting = (key: string) => T | undefined diff --git a/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts b/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts index 6639b1d0e..827e5105a 100644 --- a/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts +++ b/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts @@ -32,6 +32,7 @@ export interface AcpProcessHandle extends AgentProcessHandle { workdir: string availableModes?: Array<{ id: string; name: string; description: string }> currentModeId?: string + mcpCapabilities?: schema.McpCapabilities } interface AcpProcessManagerOptions { @@ -524,6 +525,14 @@ export class AcpProcessManager implements AgentProcessManager currentModeId?: string } + agentCapabilities?: { + mcpCapabilities?: schema.McpCapabilities + } + } + + if (resultData.agentCapabilities?.mcpCapabilities) { + handleSeed.mcpCapabilities = resultData.agentCapabilities.mcpCapabilities + console.info('[ACP] MCP capabilities:', resultData.agentCapabilities.mcpCapabilities) } if (resultData.sessionId) { @@ -580,7 +589,8 @@ export class AcpProcessManager implements AgentProcessManager { diff --git a/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts b/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts index c02c31072..69f763bf7 100644 --- a/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts +++ b/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts @@ -1,5 +1,5 @@ import { app } from 'electron' -import type { AcpAgentConfig } from '@shared/presenter' +import type { AcpAgentConfig, IConfigPresenter } from '@shared/presenter' import type { AgentSessionState } from './types' import type { AcpProcessManager, @@ -9,11 +9,15 @@ import type { } from './acpProcessManager' import type { ClientSideConnection as ClientSideConnectionType } from '@agentclientprotocol/sdk' import { AcpSessionPersistence } from './acpSessionPersistence' +import { convertMcpConfigToAcpFormat } from './mcpConfigConverter' +import { filterMcpServersByTransportSupport } from './mcpTransportFilter' +import type * as schema from '@agentclientprotocol/sdk/dist/schema.js' interface AcpSessionManagerOptions { providerId: string processManager: AcpProcessManager sessionPersistence: AcpSessionPersistence + configPresenter: IConfigPresenter } interface SessionHooks { @@ -34,6 +38,7 @@ export class AcpSessionManager { private readonly providerId: string private readonly processManager: AcpProcessManager private readonly sessionPersistence: AcpSessionPersistence + private readonly configPresenter: IConfigPresenter private readonly sessionsByConversation = new Map() private readonly sessionsById = new Map() private readonly pendingSessions = new Map>() @@ -42,6 +47,7 @@ export class AcpSessionManager { this.providerId = options.providerId this.processManager = options.processManager this.sessionPersistence = options.sessionPersistence + this.configPresenter = options.configPresenter app.on('before-quit', () => { void this.clearAllSessions() @@ -267,9 +273,53 @@ export class AcpSessionManager { currentModeId?: string }> { try { + let mcpServers: schema.McpServer[] = [] + try { + const selections = await this.configPresenter.getAgentMcpSelections(agent.id) + if (selections.length > 0) { + const serverConfigs = await this.configPresenter.getMcpServers() + const converted = selections + .map((name) => { + const cfg = serverConfigs[name] + if (!cfg) return null + return convertMcpConfigToAcpFormat(name, cfg) + }) + .filter((item): item is schema.McpServer => Boolean(item)) + + mcpServers = filterMcpServersByTransportSupport(converted, handle.mcpCapabilities) + + if (converted.length !== mcpServers.length) { + console.info(`[ACP] Filtered MCP servers by transport support for agent ${agent.id}:`, { + selected: selections, + converted: converted.map((s) => + 'type' in s ? `${s.name}:${s.type}` : `${s.name}:stdio` + ), + passed: mcpServers.map((s) => + 'type' in s ? `${s.name}:${s.type}` : `${s.name}:stdio` + ) + }) + } else { + console.info(`[ACP] Passing MCP servers to agent ${agent.id}:`, { + selected: selections, + passed: mcpServers.map((s) => + 'type' in s ? `${s.name}:${s.type}` : `${s.name}:stdio` + ) + }) + } + } else { + console.info(`[ACP] No MCP selections for agent ${agent.id}; passing none.`) + } + } catch (error) { + console.warn( + `[ACP] Failed to resolve MCP servers for agent ${agent.id}; passing none.`, + error + ) + mcpServers = [] + } + const response = await handle.connection.newSession({ cwd: workdir, - mcpServers: [] + mcpServers }) // Extract modes from response if available diff --git a/src/main/presenter/llmProviderPresenter/agent/mcpConfigConverter.ts b/src/main/presenter/llmProviderPresenter/agent/mcpConfigConverter.ts new file mode 100644 index 000000000..d6ff4ab49 --- /dev/null +++ b/src/main/presenter/llmProviderPresenter/agent/mcpConfigConverter.ts @@ -0,0 +1,59 @@ +import type * as schema from '@agentclientprotocol/sdk/dist/schema.js' +import type { MCPServerConfig } from '@shared/presenter' + +const normalizeStringRecordToArray = ( + record: Record | undefined | null +): Array<{ name: string; value: string }> => { + if (!record || typeof record !== 'object') return [] + return Object.entries(record) + .map(([name, value]) => ({ + name: name?.toString().trim(), + value: typeof value === 'string' ? value : String(value ?? '') + })) + .filter((entry) => entry.name.length > 0) +} + +const normalizeHeaders = ( + record: Record | undefined | null +): Array<{ name: string; value: string }> => { + if (!record || typeof record !== 'object') return [] + return Object.entries(record) + .map(([name, value]) => ({ + name: name?.toString().trim(), + value: value?.toString() ?? '' + })) + .filter((entry) => entry.name.length > 0) +} + +export function convertMcpConfigToAcpFormat( + serverName: string, + config: MCPServerConfig +): schema.McpServer | null { + if (!config || !serverName) return null + + if (config.type === 'inmemory') { + return null + } + + if (config.type === 'stdio') { + return { + name: serverName, + command: config.command, + args: Array.isArray(config.args) ? config.args : [], + env: normalizeStringRecordToArray(config.env) + } + } + + if (config.type === 'http' || config.type === 'sse') { + const url = config.baseUrl?.toString().trim() + if (!url) return null + return { + type: config.type, + name: serverName, + url, + headers: normalizeHeaders(config.customHeaders) + } + } + + return null +} diff --git a/src/main/presenter/llmProviderPresenter/agent/mcpTransportFilter.ts b/src/main/presenter/llmProviderPresenter/agent/mcpTransportFilter.ts new file mode 100644 index 000000000..f2cda9838 --- /dev/null +++ b/src/main/presenter/llmProviderPresenter/agent/mcpTransportFilter.ts @@ -0,0 +1,23 @@ +import type * as schema from '@agentclientprotocol/sdk/dist/schema.js' + +export function filterMcpServersByTransportSupport( + servers: schema.McpServer[], + mcpCapabilities?: schema.McpCapabilities +): schema.McpServer[] { + if (!Array.isArray(servers) || servers.length === 0) return [] + + return servers.filter((server) => { + if ('type' in server) { + if (server.type === 'http') { + return Boolean(mcpCapabilities?.http) + } + if (server.type === 'sse') { + return Boolean(mcpCapabilities?.sse) + } + return false + } + + // Stdio transport: all agents must support it. + return true + }) +} diff --git a/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts b/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts index 8d6e5ed95..107ca26fc 100644 --- a/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts +++ b/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts @@ -7,6 +7,7 @@ import { StreamState } from '../types' import { RateLimitManager } from './rateLimitManager' import { ToolCallProcessor } from './toolCallProcessor' import { ToolPresenter } from '../../toolPresenter' +import { getAgentFilteredTools } from '../../mcpPresenter/agentMcpFilter' import fs from 'fs' import path from 'path' import { app } from 'electron' @@ -45,12 +46,14 @@ export class AgentLoopHandler { modelId ) - return await this.getToolPresenter().getAllToolDefinitions({ + const toolDefs = await this.getToolPresenter().getAllToolDefinitions({ enabledMcpTools: context.enabledMcpTools, chatMode, supportsVision: this.currentSupportsVision, agentWorkspacePath }) + + return await this.filterToolsForChatMode(toolDefs, chatMode, modelId) }, callTool: async (request: MCPToolCall) => { return await this.getToolPresenter().callTool(request) @@ -188,6 +191,30 @@ export class AgentLoopHandler { return lower.includes('deepseek-reasoner') || lower.includes('kimi-k2-thinking') } + private isAgentToolDefinition(tool: { server?: { name: string } }): boolean { + const name = tool.server?.name + return Boolean(name && (name === 'yo-browser' || name.startsWith('agent-'))) + } + + private async filterToolsForChatMode( + tools: Awaited>, + chatMode: 'chat' | 'agent' | 'acp agent', + agentId?: string + ): Promise>> { + if (chatMode !== 'acp agent') return tools + if (!agentId) return [] + + const agentTools = tools.filter((tool) => this.isAgentToolDefinition(tool)) + const mcpTools = tools.filter((tool) => !this.isAgentToolDefinition(tool)) + const filteredMcp = await getAgentFilteredTools( + agentId, + undefined, + mcpTools, + this.options.configPresenter + ) + return [...filteredMcp, ...agentTools] + } + async *startStreamCompletion( providerId: string, initialMessages: ChatMessage[], @@ -313,6 +340,7 @@ export class AgentLoopHandler { supportsVision: this.currentSupportsVision, agentWorkspacePath }) + const filteredToolDefs = await this.filterToolsForChatMode(toolDefs, chatMode, modelId) const canExecute = this.options.rateLimitManager.canExecuteImmediately(providerId) if (!canExecute) { @@ -346,7 +374,7 @@ export class AgentLoopHandler { modelConfig, temperature, maxTokens, - toolDefs + filteredToolDefs ) // Process the standardized stream events diff --git a/src/main/presenter/llmProviderPresenter/managers/toolCallProcessor.ts b/src/main/presenter/llmProviderPresenter/managers/toolCallProcessor.ts index 656e1d584..a8af6c92d 100644 --- a/src/main/presenter/llmProviderPresenter/managers/toolCallProcessor.ts +++ b/src/main/presenter/llmProviderPresenter/managers/toolCallProcessor.ts @@ -123,7 +123,8 @@ export class ToolCallProcessor { name: toolCall.name, arguments: toolCall.arguments }, - server: toolDef.server + server: toolDef.server, + conversationId: context.conversationId } yield { diff --git a/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts b/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts index 1f331ad7e..86c231a22 100644 --- a/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts +++ b/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts @@ -92,7 +92,8 @@ export class AcpProvider extends BaseAgentProvider< this.sessionManager = new AcpSessionManager({ providerId: provider.id, processManager: this.processManager, - sessionPersistence: this.sessionPersistence + sessionPersistence: this.sessionPersistence, + configPresenter }) void this.initWhenEnabled() diff --git a/src/main/presenter/llmProviderPresenter/providers/anthropicProvider.ts b/src/main/presenter/llmProviderPresenter/providers/anthropicProvider.ts index 04e40ecf7..23e778382 100644 --- a/src/main/presenter/llmProviderPresenter/providers/anthropicProvider.ts +++ b/src/main/presenter/llmProviderPresenter/providers/anthropicProvider.ts @@ -18,12 +18,24 @@ import { ProxyAgent } from 'undici' const OAUTH_MODEL_LIST = { data: [ + { + created_at: '2025-11-01T00:00:00Z', + display_name: 'Claude Opus 4.5', + id: 'claude-opus-4-5-20251101', + type: 'model' + }, { created_at: '2025-09-29T00:00:00Z', display_name: 'Claude Sonnet 4.5', id: 'claude-sonnet-4-5-20250929', type: 'model' }, + { + created_at: '2025-09-29T00:00:00Z', + display_name: 'Claude Opus 4.1', + id: 'claude-opus-4-1-20250805', + type: 'model' + }, { created_at: '2025-05-14T00:00:00Z', display_name: 'Claude Sonnet 4', @@ -61,7 +73,7 @@ const OAUTH_MODEL_LIST = { type: 'model' } ], - first_id: 'claude-sonnet-4-5-20250929', + first_id: 'claude-opus-4-5-20251101', has_more: false, last_id: 'claude-3-5-sonnet-20240620' } @@ -247,7 +259,8 @@ export class AnthropicProvider extends BaseLLMProvider { const headers: Record = { 'Content-Type': 'application/json', 'anthropic-version': '2023-06-01', - 'anthropic-beta': 'oauth-2025-04-20', + 'anthropic-beta': + 'oauth-2025-04-20,claude-code-20250219,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14', Authorization: `Bearer ${this.oauthToken}` } @@ -1242,7 +1255,8 @@ ${context} const headers: Record = { 'Content-Type': 'application/json', 'anthropic-version': '2023-06-01', - 'anthropic-beta': 'oauth-2025-04-20', + 'anthropic-beta': + 'oauth-2025-04-20,claude-code-20250219,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14', Authorization: `Bearer ${this.oauthToken}`, Accept: 'text/event-stream' } diff --git a/src/main/presenter/mcpPresenter/agentMcpFilter.ts b/src/main/presenter/mcpPresenter/agentMcpFilter.ts new file mode 100644 index 000000000..5a518ffe0 --- /dev/null +++ b/src/main/presenter/mcpPresenter/agentMcpFilter.ts @@ -0,0 +1,16 @@ +import type { IConfigPresenter, MCPToolDefinition } from '@shared/presenter' + +export async function getAgentFilteredTools( + agentId: string, + isBuiltin: boolean | undefined, + allTools: MCPToolDefinition[], + configPresenter: IConfigPresenter +): Promise { + if (!agentId) return [] + + const selections = await configPresenter.getAgentMcpSelections(agentId, isBuiltin) + if (!selections?.length) return [] + + const selectionSet = new Set(selections) + return allTools.filter((tool) => selectionSet.has(tool.server?.name)) +} diff --git a/src/main/presenter/mcpPresenter/toolManager.ts b/src/main/presenter/mcpPresenter/toolManager.ts index ccdad017c..bbd6ed5b5 100644 --- a/src/main/presenter/mcpPresenter/toolManager.ts +++ b/src/main/presenter/mcpPresenter/toolManager.ts @@ -13,6 +13,7 @@ import { ServerManager } from './serverManager' import { McpClient } from './mcpClient' import { jsonrepair } from 'jsonrepair' import { getErrorMessageLabels } from '@shared/i18n' +import { presenter } from '@/presenter' export class ToolManager { private configPresenter: IConfigPresenter @@ -339,6 +340,36 @@ export class ToolManager { const { client: targetClient, originalName } = targetInfo const toolServerName = targetClient.serverName + // ACP agent-level MCP access control (only applies in "acp agent" chat mode) + if (toolCall.conversationId) { + const chatMode = this.configPresenter.getSetting<'chat' | 'agent' | 'acp agent'>( + 'input_chatMode' + ) + if (chatMode === 'acp agent') { + try { + const conversation = await presenter.threadPresenter.getConversation( + toolCall.conversationId + ) + const agentId = conversation?.settings?.modelId + if (typeof agentId === 'string' && agentId.trim().length > 0) { + const selections = await this.configPresenter.getAgentMcpSelections(agentId) + if (!selections?.length || !selections.includes(toolServerName)) { + return { + toolCallId: toolCall.id, + content: `MCP server '${toolServerName}' is not allowed for ACP agent '${agentId}'. Configure MCP access in ACP settings.`, + isError: true + } + } + } + } catch (error) { + console.warn( + '[ToolManager] Failed to resolve ACP agent context for MCP access control:', + error + ) + } + } + } + // Log the call details including original name console.info('[MCP] ToolManager calling tool', { requestedName: finalName, diff --git a/src/main/presenter/threadPresenter/managers/conversationManager.ts b/src/main/presenter/threadPresenter/managers/conversationManager.ts index 90e15e1a0..31b353729 100644 --- a/src/main/presenter/threadPresenter/managers/conversationManager.ts +++ b/src/main/presenter/threadPresenter/managers/conversationManager.ts @@ -183,6 +183,8 @@ export class ConversationManager { defaultSettings.forcedSearch = undefined defaultSettings.searchStrategy = undefined defaultSettings.selectedVariantsMap = {} + defaultSettings.acpWorkdirMap = {} + defaultSettings.agentWorkspacePath = null } const sanitizedSettings: Partial = { ...settings } diff --git a/src/main/presenter/threadPresenter/utils/promptBuilder.ts b/src/main/presenter/threadPresenter/utils/promptBuilder.ts index e2b5cfda3..d6da46cb3 100644 --- a/src/main/presenter/threadPresenter/utils/promptBuilder.ts +++ b/src/main/presenter/threadPresenter/utils/promptBuilder.ts @@ -925,5 +925,5 @@ function enhanceSystemPromptWithDateTime( hour12: false }) - return `${systemPrompt}\nToday's date and time is ${currentDateTime}` + return `${systemPrompt}\nToday is ${currentDateTime}` } diff --git a/src/renderer/settings/components/AcpSettings.vue b/src/renderer/settings/components/AcpSettings.vue index 5e515b1b0..0ba45054e 100644 --- a/src/renderer/settings/components/AcpSettings.vue +++ b/src/renderer/settings/components/AcpSettings.vue @@ -62,6 +62,22 @@
{{ agent.name }} + + + + + {{ + t('settings.acp.mcpAccessBadge', { + count: getMcpSelectionCount(agent) + }) + }} + + + +

{{ getMcpSelectionTooltip(agent) }}

+
+
+
{{ t('settings.acp.disabledBadge') }} @@ -118,6 +134,11 @@
+
-

{{ t('mcp.tools.disabled') }}

-

{{ t('mcp.tools.loading') }}

-

{{ t('mcp.tools.error') }}

-

- {{ t('mcp.tools.available', { count: getTotalEnabledToolCount() }) }} -

-

{{ t('mcp.tools.none') }}

+ +
+
+ {{ t('mcp.tools.acpManagedHint') }} +
-
+
{{ t('mcp.tools.enabled') }}
@@ -154,7 +194,7 @@ const getLocalizedServerName = (serverName: string) => {
-
+
{{ t('mcp.tools.enableToUse') }}