diff --git a/lib/app/app_controller_desktop_core.dart b/lib/app/app_controller_desktop_core.dart index 17344420..6e09bf46 100644 --- a/lib/app/app_controller_desktop_core.dart +++ b/lib/app/app_controller_desktop_core.dart @@ -43,7 +43,6 @@ import 'task_thread_repositories.dart'; import 'app_controller_desktop_navigation.dart'; import 'app_controller_desktop_gateway.dart'; import 'app_controller_desktop_settings.dart'; -import 'app_controller_desktop_single_agent.dart'; import 'app_controller_desktop_thread_sessions.dart'; import 'app_controller_desktop_thread_actions.dart'; import 'app_controller_desktop_workspace_execution.dart'; @@ -319,8 +318,6 @@ class AppController extends ChangeNotifier { {}; final Set aiGatewayPendingSessionKeysInternal = {}; final Set aiGatewayAbortedSessionKeysInternal = {}; - final Set singleAgentExternalCliPendingSessionKeysInternal = - {}; final Map> assistantThreadTurnQueuesInternal = >{}; bool multiAgentRunPendingInternal = false; @@ -483,9 +480,7 @@ class AppController extends ChangeNotifier { bool get hasPendingSettingsApply => pendingSettingsApplyInternal; String get settingsDraftStatusMessage => settingsDraftStatusMessageInternal; List get agents => agentsControllerInternal.agents; - List get sessions => isSingleAgentMode - ? assistantSessionSummariesInternal() - : sessionsControllerInternal.sessions; + List get sessions => sessionsControllerInternal.sessions; List get assistantSessions => assistantSessionsInternal(); List get instances => @@ -523,8 +518,6 @@ class AppController extends ChangeNotifier { settingsControllerInternal.effectiveAiGatewayBaseUrl.trim(); bool get hasStoredAiGatewayApiKey => settingsControllerInternal.hasEffectiveAiGatewayApiKey; - bool get isSingleAgentMode => - currentAssistantExecutionTarget == AssistantExecutionTarget.singleAgent; bool get isCodexBridgeBusy => isCodexBridgeBusyInternal; String? get codexBridgeError => codexBridgeErrorInternal; String? get codexRuntimeWarning => codexRuntimeWarningInternal; @@ -535,8 +528,6 @@ class AppController extends ChangeNotifier { CodexCooperationState get codexCooperationState => codexCooperationStateInternal; bool get isMultiAgentRunPending => multiAgentRunPendingInternal; - bool get showsSingleAgentRuntimeDebugMessagesInternal => - settings.experimentalDebug; bool desktopPlatformBusyInternal = false; static const String draftAiGatewayApiKeyKeyInternal = 'ai_gateway_api_key'; @@ -552,11 +543,9 @@ class AppController extends ChangeNotifier { resolvedAiGatewayModel.isNotEmpty; int get activeGatewayProfileIndexInternal { - final target = currentAssistantExecutionTarget; - if (target == AssistantExecutionTarget.singleAgent) { - return kGatewayRemoteProfileIndex; - } - return gatewayProfileIndexForExecutionTargetInternal(target); + return gatewayProfileIndexForExecutionTargetInternal( + currentAssistantExecutionTarget, + ); } bool hasStoredGatewayTokenForProfile(int profileIndex) => @@ -593,27 +582,7 @@ class AppController extends ChangeNotifier { List visibleAssistantExecutionTargets( Iterable supportedTargets, - ) { - final supported = supportedTargets.toSet(); - final visible = []; - if (supported.contains(AssistantExecutionTarget.singleAgent) && - bridgeProviderCatalog.isNotEmpty) { - visible.add(AssistantExecutionTarget.singleAgent); - } - if (supported.contains(AssistantExecutionTarget.gateway)) { - visible.add(AssistantExecutionTarget.gateway); - } - if (!supportedTargets.contains(AssistantExecutionTarget.singleAgent) || - visible.contains(AssistantExecutionTarget.singleAgent)) { - return visible; - } - return [ - AssistantExecutionTarget.singleAgent, - ...visible.where( - (target) => target != AssistantExecutionTarget.singleAgent, - ), - ]; - } + ) => const [AssistantExecutionTarget.gateway]; List get aiGatewayConversationModelChoices { final availableModels = @@ -654,9 +623,6 @@ class AppController extends ChangeNotifier { String resolvedAssistantModelForTargetInternal( AssistantExecutionTarget target, ) { - if (target == AssistantExecutionTarget.singleAgent) { - return ''; - } final resolved = resolvedDefaultModel.trim(); if (resolved.isNotEmpty) { return resolved; diff --git a/lib/app/app_controller_desktop_external_acp_routing.dart b/lib/app/app_controller_desktop_external_acp_routing.dart index f5f198bf..ba38d094 100644 --- a/lib/app/app_controller_desktop_external_acp_routing.dart +++ b/lib/app/app_controller_desktop_external_acp_routing.dart @@ -45,13 +45,7 @@ extension AppControllerDesktopExternalAcpRouting on AppController { sessionKey, ); final thread = assistantThreadRecordsInternal[normalizedSessionKey]; - final sessionTarget = assistantExecutionTargetForSession( - normalizedSessionKey, - ); - final preferredGatewayTarget = switch (sessionTarget) { - AssistantExecutionTarget.gateway => kCanonicalGatewayProviderId, - AssistantExecutionTarget.singleAgent => kCanonicalGatewayProviderId, - }; + const preferredGatewayTarget = kCanonicalGatewayProviderId; final availableSkills = assistantImportedSkillsForSession(normalizedSessionKey) .map((item) { @@ -70,11 +64,7 @@ extension AppControllerDesktopExternalAcpRouting on AppController { .where((item) => item.trim().isNotEmpty) .toList(growable: false); - final resolvedExplicitProviderId = - sessionTarget == AssistantExecutionTarget.singleAgent && - (thread?.hasExplicitProviderSelection ?? false) - ? singleAgentProviderForSession(normalizedSessionKey).providerId - : ''; + const resolvedExplicitProviderId = ''; final resolvedExplicitModel = thread?.hasExplicitModelSelection ?? false ? assistantModelForSession(normalizedSessionKey) : ''; @@ -121,7 +111,6 @@ extension AppControllerDesktopExternalAcpRouting on AppController { String _routingExecutionTargetValueInternal(AssistantExecutionTarget target) { return switch (target) { - AssistantExecutionTarget.singleAgent => 'single-agent', AssistantExecutionTarget.gateway => 'gateway', }; } diff --git a/lib/app/app_controller_desktop_runtime_coordination_impl.dart b/lib/app/app_controller_desktop_runtime_coordination_impl.dart index 48ed8d44..7adfba87 100644 --- a/lib/app/app_controller_desktop_runtime_coordination_impl.dart +++ b/lib/app/app_controller_desktop_runtime_coordination_impl.dart @@ -31,13 +31,11 @@ import '../runtime/mode_switcher.dart'; import '../runtime/agent_registry.dart'; import '../runtime/multi_agent_orchestrator.dart'; import '../runtime/platform_environment.dart'; -import '../runtime/single_agent_capabilities.dart'; import '../runtime/skill_directory_access.dart'; import 'app_controller_desktop_core.dart'; import 'app_controller_desktop_navigation.dart'; import 'app_controller_desktop_gateway.dart'; import 'app_controller_desktop_settings.dart'; -import 'app_controller_desktop_single_agent.dart'; import 'app_controller_desktop_thread_sessions.dart'; import 'app_controller_desktop_thread_actions.dart'; import 'app_controller_desktop_workspace_execution.dart'; @@ -53,19 +51,9 @@ Future refreshAcpCapabilitiesRuntimeInternal( bool persistMountTargets = false, }) async { try { - final target = controller.assistantExecutionTargetForSession( - controller.sessionsControllerInternal.currentSessionKey, + await controller.gatewayAcpClientInternal.loadCapabilities( + forceRefresh: forceRefresh, ); - if (target == AssistantExecutionTarget.singleAgent) { - await controller.goTaskServiceClientInternal.loadExternalAcpCapabilities( - target: AssistantExecutionTarget.singleAgent, - forceRefresh: forceRefresh, - ); - } else { - await controller.gatewayAcpClientInternal.loadCapabilities( - forceRefresh: forceRefresh, - ); - } } catch (_) { // Keep mount refresh resilient when ACP is temporarily unavailable. } @@ -91,19 +79,7 @@ Future refreshAcpCapabilitiesRuntimeInternal( Future refreshSingleAgentCapabilitiesRuntimeInternal( AppController controller, { bool forceRefresh = false, -}) async { - final capabilities = await controller.goTaskServiceClientInternal - .loadExternalAcpCapabilities( - target: AssistantExecutionTarget.singleAgent, - forceRefresh: forceRefresh, - ); - controller.bridgeProviderCatalogInternal = normalizeSingleAgentProviderList( - capabilities.providerCatalog, - ); - if (!controller.disposedInternal) { - controller.notifyListeners(); - } -} +}) async {} List mergeAcpCapabilitiesIntoMountTargetsRuntimeInternal( @@ -192,42 +168,6 @@ String? resolveLocalAssistantWorkingDirectoryForSessionRuntimeInternal( return candidate; } -String? resolveSingleAgentWorkingDirectoryForSessionRuntimeInternal( - AppController controller, - String sessionKey, { - SingleAgentProvider? provider, -}) { - final requiresLocalPath = - provider == null || - singleAgentProviderRequiresLocalPathRuntimeInternal(controller, provider); - final record = - controller.assistantThreadRecordsInternal[controller - .normalizedAssistantSessionKeyInternal(sessionKey)]; - if (!requiresLocalPath && record?.workspaceKind == WorkspaceKind.remoteFs) { - return assistantWorkingDirectoryForSessionRuntimeInternal( - controller, - sessionKey, - ); - } - return resolveLocalAssistantWorkingDirectoryForSessionRuntimeInternal( - controller, - sessionKey, - requireLocalExistence: requiresLocalPath, - ); -} - -bool singleAgentProviderRequiresLocalPathRuntimeInternal( - AppController _, - SingleAgentProvider provider, -) { - if (provider == SingleAgentProvider.codex || - provider == SingleAgentProvider.opencode || - provider == SingleAgentProvider.gemini) { - return false; - } - return true; -} - CodeAgentNodeState buildCodeAgentNodeStateRuntimeInternal( AppController controller, ) { @@ -247,7 +187,6 @@ GatewayMode bridgeGatewayModeRuntimeInternal(AppController controller) { return GatewayMode.offline; } return switch (controller.currentAssistantExecutionTarget) { - AssistantExecutionTarget.singleAgent => GatewayMode.offline, AssistantExecutionTarget.gateway => GatewayMode.remote, }; } diff --git a/lib/app/app_controller_desktop_runtime_helpers.dart b/lib/app/app_controller_desktop_runtime_helpers.dart index 2f931f65..fa434071 100644 --- a/lib/app/app_controller_desktop_runtime_helpers.dart +++ b/lib/app/app_controller_desktop_runtime_helpers.dart @@ -226,36 +226,9 @@ extension AppControllerDesktopRuntimeHelpers on AppController { }) { final raw = error.toString().trim(); final lowered = raw.toLowerCase(); - if ((lowered.contains('acp_endpoint_missing') || - lowered.contains('missing acp endpoint')) && - target == AssistantExecutionTarget.singleAgent) { - return appText( - '当前线程缺少可用的 Bridge Server,暂时无法继续。', - 'This thread does not have an available bridge server yet.', - ); - } if (lowered.contains('gateway not connected') || lowered.contains('code: offline') || lowered.contains('offlin') && lowered.contains('gateway')) { - if (target == AssistantExecutionTarget.singleAgent) { - final selection = singleAgentProviderForSession( - sessionsControllerInternal.currentSessionKey, - ); - final provider = currentSingleAgentResolvedProvider ?? selection; - final providerLabel = provider.isUnspecified - ? appText('Bridge Provider', 'Bridge Provider') - : provider.label; - final address = _extractGatewayAddressFromErrorInternal(raw); - return address.isEmpty - ? appText( - '当前线程的 Bridge Provider($providerLabel)未连接。请先恢复该 Provider 对应连接后再重试。', - 'The Bridge Provider for this thread ($providerLabel) is offline. Restore that provider connection, then try again.', - ) - : appText( - '当前线程的 Bridge Provider($providerLabel)未连接:$address。请先恢复该 Provider 对应连接后再重试。', - 'The Bridge Provider for this thread ($providerLabel) is offline: $address. Restore that provider connection, then try again.', - ); - } final profile = gatewayProfileForAssistantExecutionTargetInternal(target); final address = gatewayAddressLabelInternal(profile); return address == appText('未连接目标', 'No target') @@ -271,13 +244,6 @@ extension AppControllerDesktopRuntimeHelpers on AppController { return raw; } - String _extractGatewayAddressFromErrorInternal(String raw) { - final match = RegExp( - r'((?:\d{1,3}\.){3}\d{1,3}:\d+|localhost:\d+|[a-zA-Z0-9.-]+:\d+)', - ).firstMatch(raw); - return match?.group(1)?.trim() ?? ''; - } - String formatAiGatewayHttpErrorInternal(int statusCode, String detail) { final base = switch (statusCode) { 400 => appText( @@ -477,19 +443,6 @@ extension AppControllerDesktopRuntimeHelpers on AppController { requireLocalExistence: requireLocalExistence, ); - String? resolveSingleAgentWorkingDirectoryForSessionInternal( - String sessionKey, { - SingleAgentProvider? provider, - }) => resolveSingleAgentWorkingDirectoryForSessionRuntimeInternal( - this, - sessionKey, - provider: provider, - ); - - bool singleAgentProviderRequiresLocalPathInternal( - SingleAgentProvider provider, - ) => singleAgentProviderRequiresLocalPathRuntimeInternal(this, provider); - void registerCodexExternalProviderInternal() { runtimeCoordinatorInternal.registerExternalCodeAgent( ExternalCodeAgentProvider( @@ -611,10 +564,6 @@ extension AppControllerDesktopRuntimeHelpers on AppController { if (disposedInternal) { return; } - if (assistantExecutionTargetForSession(currentSessionKey) == - AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession(currentSessionKey); - } } notifyIfActiveInternal(); } @@ -800,35 +749,16 @@ extension AppControllerDesktopRuntimeHelpers on AppController { AssistantExecutionTarget assistantExecutionTargetForModeInternal( RuntimeConnectionMode mode, ) { - return switch (mode) { - RuntimeConnectionMode.unconfigured => - AssistantExecutionTarget.singleAgent, - RuntimeConnectionMode.local => AssistantExecutionTarget.gateway, - RuntimeConnectionMode.remote => AssistantExecutionTarget.gateway, - }; + return AssistantExecutionTarget.gateway; } GatewayConnectionProfile gatewayProfileForAssistantExecutionTargetInternal( AssistantExecutionTarget target, - ) { - return switch (target) { - AssistantExecutionTarget.gateway => settings.primaryGatewayProfile, - AssistantExecutionTarget.singleAgent => throw StateError( - 'Single Agent target has no gateway profile.', - ), - }; - } + ) => settings.primaryGatewayProfile; int gatewayProfileIndexForExecutionTargetInternal( AssistantExecutionTarget target, - ) { - return switch (target) { - AssistantExecutionTarget.gateway => kGatewayRemoteProfileIndex, - AssistantExecutionTarget.singleAgent => throw StateError( - 'Single Agent target has no gateway profile index.', - ), - }; - } + ) => kGatewayRemoteProfileIndex; } String _sanitizeArtifactRelativePathInternal(String raw) { diff --git a/lib/app/app_controller_desktop_settings.dart b/lib/app/app_controller_desktop_settings.dart index f926a56b..b3df783a 100644 --- a/lib/app/app_controller_desktop_settings.dart +++ b/lib/app/app_controller_desktop_settings.dart @@ -296,7 +296,6 @@ extension AppControllerDesktopSettings on AppController { aiGatewayStreamingClientsInternal.clear(); aiGatewayPendingSessionKeysInternal.clear(); aiGatewayAbortedSessionKeysInternal.clear(); - singleAgentExternalCliPendingSessionKeysInternal.clear(); assistantThreadTurnQueuesInternal.clear(); multiAgentRunPendingInternal = false; initializeAssistantThreadContext( @@ -305,7 +304,6 @@ extension AppControllerDesktopSettings on AppController { currentSettings.assistantExecutionTarget, ), messageViewMode: AssistantMessageViewMode.rendered, - singleAgentProvider: SingleAgentProvider.unspecified, ); await setCurrentAssistantSessionKeyInternal( 'main', diff --git a/lib/app/app_controller_desktop_settings_runtime.dart b/lib/app/app_controller_desktop_settings_runtime.dart index 0771d527..f1777487 100644 --- a/lib/app/app_controller_desktop_settings_runtime.dart +++ b/lib/app/app_controller_desktop_settings_runtime.dart @@ -283,13 +283,12 @@ extension AppControllerDesktopSettingsRuntime on AppController { String tokenOverride = '', String passwordOverride = '', }) async { - if (executionTarget == AssistantExecutionTarget.singleAgent || - profile.mode == RuntimeConnectionMode.unconfigured) { + if (profile.mode == RuntimeConnectionMode.unconfigured) { return ( state: 'inactive', message: appText( - '当前模式使用单机智能体,不建立 OpenClaw Gateway 会话。', - 'The current mode uses Single Agent and does not open an OpenClaw Gateway session.', + '当前未配置可用 Gateway 连接。', + 'No active gateway connection is configured.', ), endpoint: '', ); @@ -408,8 +407,6 @@ extension AppControllerDesktopSettingsRuntime on AppController { } await refreshAcpCapabilitiesInternal(forceRefresh: true); - await refreshSingleAgentCapabilitiesInternal(forceRefresh: true); - await runtimeCoordinatorInternal.configureCodexForGateway( gatewayUrl: gatewayUrl, apiKey: apiKey, @@ -527,7 +524,6 @@ extension AppControllerDesktopSettingsRuntime on AppController { settings.launchAtLogin, ); registerCodexExternalProviderInternal(); - await refreshSingleAgentCapabilitiesInternal(); await refreshAcpCapabilitiesInternal(persistMountTargets: true); if (disposedInternal) { return; @@ -550,9 +546,6 @@ extension AppControllerDesktopSettingsRuntime on AppController { await ensureActiveAssistantThreadInternal(); await ensureDesktopTaskThreadBindingInternal(currentSessionKey); unawaited(startupRefreshSharedSingleAgentLocalSkillsCacheInternal()); - if (isSingleAgentMode) { - await refreshSingleAgentSkillsForSession(currentSessionKey); - } runtimeEventsSubscriptionInternal = runtimeCoordinatorInternal .gateway .events @@ -561,7 +554,6 @@ extension AppControllerDesktopSettingsRuntime on AppController { startupTarget, ); final shouldAutoConnect = - startupTarget != AssistantExecutionTarget.singleAgent && startupProfile != null && startupProfile.useSetupCode && startupProfile.setupCode.trim().isNotEmpty; @@ -789,7 +781,6 @@ extension AppControllerDesktopSettingsRuntime on AppController { if (previous.codeAgentRuntimeMode != current.codeAgentRuntimeMode) { registerCodexExternalProviderInternal(); } - unawaited(refreshSingleAgentCapabilitiesInternal().catchError((_) {})); if (previous.linuxDesktop.toJson().toString() != current.linuxDesktop.toJson().toString() || previous.launchAtLogin != current.launchAtLogin) { @@ -806,20 +797,12 @@ extension AppControllerDesktopSettingsRuntime on AppController { if (disposedInternal) { return; } - if (assistantExecutionTargetForSession(currentSessionKey) == - AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession(currentSessionKey); - } } if (previous.workspacePath != current.workspacePath) { await ensureDesktopTaskThreadBindingInternal(currentSessionKey); if (disposedInternal) { return; } - if (assistantExecutionTargetForSession(currentSessionKey) == - AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession(currentSessionKey); - } } if (refreshAfterSave) { recomputeTasksInternal(); @@ -855,9 +838,6 @@ extension AppControllerDesktopSettingsRuntime on AppController { sessionKey: sessionKey, persistDefaultSelection: false, ); - if (target == AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession(sessionKey); - } recomputeTasksInternal(); notifyIfActiveInternal(); } diff --git a/lib/app/app_controller_desktop_single_agent.dart b/lib/app/app_controller_desktop_single_agent.dart index 663620c2..3ed0e568 100644 --- a/lib/app/app_controller_desktop_single_agent.dart +++ b/lib/app/app_controller_desktop_single_agent.dart @@ -1,25 +1,3 @@ import 'app_controller_desktop_core.dart'; -import 'app_controller_desktop_single_agent_go_task_flow.dart'; -import 'app_controller_desktop_single_agent_status_messages.dart'; -import '../runtime/runtime_models.dart'; -extension AppControllerDesktopSingleAgent on AppController { - Future sendSingleAgentMessageInternal( - String message, { - required String thinking, - required List attachments, - required List localAttachments, - }) { - return sendSingleAgentMessageDesktopGoTaskFlowInternal( - this, - message, - thinking: thinking, - attachments: attachments, - localAttachments: localAttachments, - ); - } - - GatewayChatMessage assistantErrorMessageInternal(String text) { - return assistantErrorMessageSingleAgentDesktopInternal(this, text); - } -} +extension AppControllerDesktopSingleAgent on AppController {} diff --git a/lib/app/app_controller_desktop_single_agent_go_task_flow.dart b/lib/app/app_controller_desktop_single_agent_go_task_flow.dart deleted file mode 100644 index ddeaae9f..00000000 --- a/lib/app/app_controller_desktop_single_agent_go_task_flow.dart +++ /dev/null @@ -1,329 +0,0 @@ -// ignore_for_file: unused_import, unnecessary_import - -import 'dart:async'; -import 'package:flutter/material.dart'; -import '../i18n/app_language.dart'; -import '../models/app_models.dart'; -import '../runtime/desktop_thread_artifact_sync.dart'; -import '../runtime/go_task_service_client.dart'; -import '../runtime/runtime_models.dart'; -import 'app_controller_desktop_core.dart'; -import 'app_controller_desktop_external_acp_routing.dart'; -import 'app_controller_desktop_runtime_helpers.dart'; -import 'app_controller_desktop_single_agent_status_messages.dart'; -import 'app_controller_desktop_thread_sessions.dart'; -import 'app_controller_desktop_thread_storage.dart'; -import 'app_controller_desktop_skill_permissions.dart'; - -Future sendSingleAgentMessageDesktopGoTaskFlowInternal( - AppController controller, - String message, { - required String thinking, - required List attachments, - required List localAttachments, -}) async { - final sessionKey = controller.normalizedAssistantSessionKeyInternal( - controller.sessionsControllerInternal.currentSessionKey, - ); - final trimmed = message.trim(); - if (trimmed.isEmpty && attachments.isEmpty) { - return; - } - await controller.enqueueThreadTurnInternal(sessionKey, () async { - final sessionTarget = controller.assistantExecutionTargetForSession( - sessionKey, - ); - final userText = trimmed.isEmpty ? 'See attached.' : trimmed; - controller.appendAssistantThreadMessageInternal( - sessionKey, - GatewayChatMessage( - id: controller.nextLocalMessageIdInternal(), - role: 'user', - text: userText, - timestampMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - toolCallId: null, - toolName: null, - stopReason: null, - pending: false, - error: false, - ), - ); - controller.aiGatewayPendingSessionKeysInternal.add(sessionKey); - controller.recomputeTasksInternal(); - controller.notifyIfActiveInternal(); - - try { - final routing = controller.buildExternalAcpRoutingForSessionInternal( - sessionKey, - ); - final selection = controller.singleAgentProviderForSession(sessionKey); - final preflightWorkingDirectory = controller - .resolveSingleAgentWorkingDirectoryForSessionInternal(sessionKey); - if (preflightWorkingDirectory == null || - preflightWorkingDirectory.trim().isEmpty) { - final error = StateError( - appText( - '当前线程缺少可运行的工作路径,无法启动单机智能体。', - 'This thread does not have a runnable workspace path, so Single Agent cannot start.', - ), - ); - controller.appendAssistantThreadMessageInternal( - sessionKey, - assistantErrorMessageSingleAgentDesktopInternal( - controller, - error.message, - ), - ); - throw error; - } - if (controller.resolveExternalAcpEndpointForTargetInternal( - AssistantExecutionTarget.singleAgent, - ) == - null) { - controller.upsertTaskThreadInternal( - sessionKey, - lifecycleStatus: 'ready', - lastRunAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - lastResultCode: 'error', - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - controller.appendAssistantThreadMessageInternal( - sessionKey, - assistantErrorMessageSingleAgentDesktopInternal( - controller, - appText( - 'Bridge ACP 入口当前不可用。', - 'The bridge ACP entrypoint is currently unavailable.', - ), - ), - ); - return; - } - final routingResolution = await controller.goTaskServiceClientInternal - .resolveExternalAcpRouting( - taskPrompt: message, - workingDirectory: preflightWorkingDirectory, - routing: routing, - ); - final resolvedProviderId = routingResolution.resolvedProviderId.trim(); - final resolvedProvider = resolvedProviderId.isEmpty - ? null - : controller.bridgeProviderForId(resolvedProviderId) ?? - SingleAgentProviderCopy.fromJsonValue(resolvedProviderId); - final effectiveProvider = resolvedProvider ?? selection; - controller.upsertTaskThreadInternal( - sessionKey, - latestResolvedProviderId: resolvedProviderId, - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - final unavailableReason = routingResolution.unavailable - ? singleAgentUnavailableLabelDesktopInternal( - controller, - sessionKey, - routingResolution.unavailableMessage, - ) - : resolvedProviderId.isEmpty && effectiveProvider.isUnspecified - ? singleAgentUnavailableLabelDesktopInternal( - controller, - sessionKey, - appText( - 'Bridge 当前没有广告可用 Provider。', - 'The bridge is not advertising any available providers.', - ), - ) - : null; - if (unavailableReason != null) { - controller.upsertTaskThreadInternal( - sessionKey, - lifecycleStatus: 'ready', - lastRunAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - lastResultCode: 'error', - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - controller.appendAssistantThreadMessageInternal( - sessionKey, - assistantErrorMessageSingleAgentDesktopInternal( - controller, - unavailableReason, - ), - ); - return; - } - - if (!effectiveProvider.isUnspecified) { - appendSingleAgentRuntimeStatusDesktopInternal( - controller, - sessionKey, - effectiveProvider, - ); - } - final workingDirectory = controller - .resolveSingleAgentWorkingDirectoryForSessionInternal( - sessionKey, - provider: effectiveProvider.isUnspecified - ? null - : effectiveProvider, - ); - final resolvedWorkingDirectory = - workingDirectory == null || workingDirectory.trim().isEmpty - ? preflightWorkingDirectory - : workingDirectory; - - final selectedSkills = controller - .assistantSelectedSkillsForSession(sessionKey) - .map((item) => item.label.trim().isNotEmpty ? item.label : item.key) - .where((item) => item.trim().isNotEmpty) - .toList(growable: false); - final result = await controller.goTaskServiceClientInternal.executeTask( - GoTaskServiceRequest( - sessionId: sessionKey, - threadId: sessionKey, - target: AssistantExecutionTarget.singleAgent, - prompt: message, - workingDirectory: resolvedWorkingDirectory, - model: controller.assistantModelForSession(sessionKey), - thinking: thinking, - selectedSkills: selectedSkills, - inlineAttachments: attachments, - localAttachments: localAttachments, - agentId: '', - metadata: const {}, - routing: routing, - routingHint: 'single-agent', - provider: effectiveProvider, - remoteWorkingDirectoryHint: - controller - .requireTaskThreadForSessionInternal(sessionKey) - .lastRemoteWorkingDirectory ?? - '', - ), - onUpdate: (update) { - if (update.isDelta) { - controller.appendAiGatewayStreamingTextInternal( - sessionKey, - update.text, - ); - controller.notifyIfActiveInternal(); - } - }, - ); - await _applySingleAgentGoTaskResultDesktopInternal( - controller, - sessionKey: sessionKey, - sessionTarget: sessionTarget, - message: message, - thinking: thinking, - attachments: attachments, - result: result, - ); - } catch (error) { - controller.clearAiGatewayStreamingTextInternal(sessionKey); - controller.upsertTaskThreadInternal( - sessionKey, - lifecycleStatus: 'ready', - lastRunAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - lastResultCode: 'error', - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - controller.appendAssistantThreadMessageInternal( - sessionKey, - assistantErrorMessageSingleAgentDesktopInternal( - controller, - controller.gatewayExecutionErrorLabelInternal( - error, - target: sessionTarget, - ), - ), - ); - } finally { - controller.clearAiGatewayStreamingTextInternal(sessionKey); - controller.aiGatewayPendingSessionKeysInternal.remove(sessionKey); - controller.recomputeTasksInternal(); - controller.notifyIfActiveInternal(); - } - }); -} - -Future _applySingleAgentGoTaskResultDesktopInternal( - AppController controller, { - required String sessionKey, - required AssistantExecutionTarget sessionTarget, - required String message, - required String thinking, - required List attachments, - required GoTaskServiceResult result, -}) async { - final resolvedRuntimeModel = result.resolvedModel.trim(); - final resolvedGatewayEntryState = goTaskServiceGatewayEntryState( - requestedTarget: sessionTarget, - result: result, - ); - controller.upsertTaskThreadInternal( - sessionKey, - gatewayEntryState: resolvedGatewayEntryState, - latestResolvedRuntimeModel: resolvedRuntimeModel, - latestResolvedProviderId: result.resolvedProviderId, - lifecycleStatus: 'ready', - lastRunAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - lastResultCode: result.success ? 'success' : 'error', - lastRemoteWorkingDirectory: result.remoteWorkingDirectory.trim().isEmpty - ? null - : result.remoteWorkingDirectory.trim(), - lastRemoteWorkspaceRefKind: result.remoteWorkspaceRefKind, - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - await _persistSingleAgentArtifactsDesktopInternal( - controller, - sessionKey, - result, - ); - controller.clearAiGatewayStreamingTextInternal(sessionKey); - if (!result.success) { - controller.appendAssistantThreadMessageInternal( - sessionKey, - assistantErrorMessageSingleAgentDesktopInternal( - controller, - appText( - 'GoTaskService 执行失败:${result.errorMessage}', - 'GoTaskService execution failed: ${result.errorMessage}', - ), - ), - ); - return; - } - - if (result.message.trim().isEmpty) { - controller.appendAssistantThreadMessageInternal( - sessionKey, - assistantErrorMessageSingleAgentDesktopInternal( - controller, - appText( - 'GoTaskService 没有返回可显示的输出。', - 'GoTaskService returned no displayable output.', - ), - ), - ); - return; - } - - controller.appendAssistantThreadMessageInternal( - sessionKey, - GatewayChatMessage( - id: controller.nextLocalMessageIdInternal(), - role: 'assistant', - text: result.message, - timestampMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - toolCallId: null, - toolName: null, - stopReason: null, - pending: false, - error: false, - ), - ); -} - -Future _persistSingleAgentArtifactsDesktopInternal( - AppController controller, - String sessionKey, - GoTaskServiceResult result, -) => controller.persistGoTaskArtifactsForSessionInternal(sessionKey, result); diff --git a/lib/app/app_controller_desktop_single_agent_status_messages.dart b/lib/app/app_controller_desktop_single_agent_status_messages.dart deleted file mode 100644 index 39da6f26..00000000 --- a/lib/app/app_controller_desktop_single_agent_status_messages.dart +++ /dev/null @@ -1,116 +0,0 @@ -// ignore_for_file: unused_import, unnecessary_import - -import 'package:flutter/material.dart'; -import '../i18n/app_language.dart'; -import '../runtime/runtime_models.dart'; -import 'app_controller_desktop_core.dart'; -import 'app_controller_desktop_runtime_helpers.dart'; -import 'app_controller_desktop_thread_sessions.dart'; -import 'app_controller_desktop_thread_storage.dart'; - -GatewayChatMessage assistantErrorMessageSingleAgentDesktopInternal( - AppController controller, - String text, -) { - return GatewayChatMessage( - id: controller.nextLocalMessageIdInternal(), - role: 'assistant', - text: text, - timestampMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - toolCallId: null, - toolName: null, - stopReason: null, - pending: false, - error: true, - ); -} - -String? singleAgentRuntimeDebugToolNameDesktopInternal( - AppController controller, - String label, -) { - if (!controller.showsSingleAgentRuntimeDebugMessagesInternal) { - return null; - } - final trimmed = label.trim(); - if (trimmed.isEmpty) { - return null; - } - return trimmed; -} - -void appendSingleAgentRuntimeStatusDesktopInternal( - AppController controller, - String sessionKey, - SingleAgentProvider provider, -) { - if (!controller.showsSingleAgentRuntimeDebugMessagesInternal) { - return; - } - controller.appendAssistantThreadMessageInternal( - sessionKey, - GatewayChatMessage( - id: controller.nextLocalMessageIdInternal(), - role: 'assistant', - text: appText( - '单机智能体已切换到 ${provider.label} 执行当前任务。', - 'Single Agent is using ${provider.label} for this task.', - ), - timestampMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - toolCallId: null, - toolName: provider.label, - stopReason: null, - pending: false, - error: false, - ), - ); -} - -String singleAgentUnavailableLabelDesktopInternal( - AppController controller, - String sessionKey, - String? reason, -) { - final normalizedSessionKey = controller.normalizedAssistantSessionKeyInternal( - sessionKey, - ); - final detail = reason?.trim() ?? ''; - final selection = - controller.currentSingleAgentResolvedProvider ?? - controller.singleAgentProviderForSession(normalizedSessionKey); - if (controller.singleAgentShouldSuggestAcpSwitchForSession( - normalizedSessionKey, - )) { - return detail.isEmpty - ? appText( - '当前线程固定为 ${selection.label},但它在这台设备上不可用。检测到其他 Bridge Provider 时不会自动改线,请手动切到可用 Provider。', - 'This thread is pinned to ${selection.label}, but it is unavailable on this device. XWorkmate will not reroute to another bridge provider automatically. Switch to an available provider manually.', - ) - : appText( - '当前线程固定为 ${selection.label}:$detail 检测到其他 Bridge Provider 时不会自动改线,请手动切到可用 Provider。', - 'This thread is pinned to ${selection.label}: $detail XWorkmate will not reroute to another bridge provider automatically. Switch to an available provider manually.', - ); - } - if (controller.singleAgentNeedsBridgeProviderForSession( - normalizedSessionKey, - )) { - return detail.isEmpty - ? appText( - 'Bridge 当前没有可用 Provider。', - 'The bridge does not currently advertise any available providers.', - ) - : appText( - '$detail Bridge 当前没有可用 Provider。', - '$detail The bridge does not currently advertise any available providers.', - ); - } - return detail.isEmpty - ? appText( - '当前线程的 Bridge Provider 尚未就绪。', - 'The bridge provider for this thread is not ready yet.', - ) - : appText( - '当前线程的 Bridge Provider 尚未就绪:$detail', - 'The bridge provider for this thread is not ready yet: $detail', - ); -} diff --git a/lib/app/app_controller_desktop_skill_permissions.dart b/lib/app/app_controller_desktop_skill_permissions.dart index 75ba819d..9a33e740 100644 --- a/lib/app/app_controller_desktop_skill_permissions.dart +++ b/lib/app/app_controller_desktop_skill_permissions.dart @@ -96,11 +96,6 @@ extension AppControllerDesktopSkillPermissions on AppController { if (disposedInternal) { return; } - if (assistantExecutionTargetForSession(currentSessionKey) == - AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession(currentSessionKey); - return; - } notifyIfActiveInternal(); } @@ -255,10 +250,8 @@ extension AppControllerDesktopSkillPermissions on AppController { final nextExecutionTarget = executionTarget ?? switch (existing?.executionBinding.executionMode) { - ThreadExecutionMode.localAgent => - AssistantExecutionTarget.singleAgent, ThreadExecutionMode.gateway => AssistantExecutionTarget.gateway, - null => AssistantExecutionTarget.singleAgent, + null => AssistantExecutionTarget.gateway, }; final nextImportedSkills = importedSkills ?? @@ -286,47 +279,30 @@ extension AppControllerDesktopSkillPermissions on AppController { final nextWorkspaceBinding = workspaceBinding ?? existing?.workspaceBinding ?? - (nextExecutionTarget == AssistantExecutionTarget.singleAgent - ? buildDesktopWorkspaceBindingInternal( - normalizedSessionKey, - executionTarget: nextExecutionTarget, - ownerScope: nextOwnerScope, - existingBinding: null, - ) - : null); - if (nextWorkspaceBinding == null || !nextWorkspaceBinding.isComplete) { + buildDesktopWorkspaceBindingInternal( + normalizedSessionKey, + executionTarget: nextExecutionTarget, + ownerScope: nextOwnerScope, + existingBinding: null, + ); + if (!nextWorkspaceBinding.isComplete) { throw StateError( 'TaskThread $normalizedSessionKey is missing a complete workspaceBinding.', ); } - final nextProvider = - nextExecutionTarget == AssistantExecutionTarget.singleAgent - ? (singleAgentProvider ?? - SingleAgentProviderCopy.fromJsonValue( - executionBinding?.providerId ?? - existing?.executionBinding.providerId, - )) - : SingleAgentProvider.unspecified; - final nextProviderSource = - nextExecutionTarget == AssistantExecutionTarget.singleAgent - ? (singleAgentProviderSource ?? - existing?.executionBinding.providerSource) - : ThreadSelectionSource.inherited; + final nextProvider = SingleAgentProvider.unspecified; + const nextProviderSource = ThreadSelectionSource.inherited; final nextExecutionBinding = (executionBinding ?? existing?.executionBinding ?? ExecutionBinding( - executionMode: ThreadExecutionMode.localAgent, + executionMode: ThreadExecutionMode.gateway, executorId: nextProvider.providerId, providerId: nextProvider.providerId, endpointId: '', )) .copyWith( - executionMode: switch (nextExecutionTarget) { - AssistantExecutionTarget.singleAgent => - ThreadExecutionMode.localAgent, - AssistantExecutionTarget.gateway => ThreadExecutionMode.gateway, - }, + executionMode: ThreadExecutionMode.gateway, executorId: nextProvider.providerId, providerId: nextProvider.providerId, executionModeSource: diff --git a/lib/app/app_controller_desktop_thread_actions.dart b/lib/app/app_controller_desktop_thread_actions.dart index b6123bcf..861b9b0f 100644 --- a/lib/app/app_controller_desktop_thread_actions.dart +++ b/lib/app/app_controller_desktop_thread_actions.dart @@ -38,7 +38,6 @@ import 'app_controller_desktop_navigation.dart'; import 'app_controller_desktop_gateway.dart'; import 'app_controller_desktop_settings.dart'; import 'app_controller_desktop_external_acp_routing.dart'; -import 'app_controller_desktop_single_agent.dart'; import 'app_controller_desktop_thread_binding.dart'; import 'app_controller_desktop_thread_sessions.dart'; import 'app_controller_desktop_workspace_execution.dart'; @@ -49,6 +48,20 @@ import 'app_controller_desktop_runtime_helpers.dart'; // ignore_for_file: invalid_use_of_visible_for_testing_member, invalid_use_of_protected_member extension AppControllerDesktopThreadActions on AppController { + GatewayChatMessage assistantErrorMessageInternal(String text) { + return GatewayChatMessage( + id: nextLocalMessageIdInternal(), + role: 'assistant', + text: text, + timestampMs: DateTime.now().millisecondsSinceEpoch.toDouble(), + toolCallId: null, + toolName: null, + stopReason: null, + pending: false, + error: true, + ); + } + bool assistantSessionHasPendingRun(String sessionKey) { final normalized = normalizedAssistantSessionKeyInternal(sessionKey); return aiGatewayPendingSessionKeysInternal.contains(normalized) || @@ -59,23 +72,8 @@ extension AppControllerDesktopThreadActions on AppController { )); } - Future sendSingleAgentMessageInternal( - String message, { - required String thinking, - required List attachments, - required List localAttachments, - }) => AppControllerDesktopSingleAgent(this).sendSingleAgentMessageInternal( - message, - thinking: thinking, - attachments: attachments, - localAttachments: localAttachments, - ); - Future connectSavedGateway() async { final target = currentAssistantExecutionTarget; - if (target == AssistantExecutionTarget.singleAgent) { - return; - } await AppControllerDesktopGateway(this).connectProfileInternal( gatewayProfileForAssistantExecutionTargetInternal(target), profileIndex: gatewayProfileIndexForExecutionTargetInternal(target), @@ -154,20 +152,17 @@ extension AppControllerDesktopThreadActions on AppController { Future selectAgent(String? agentId) async { agentsControllerInternal.selectAgent(agentId); - if (currentAssistantExecutionTarget != - AssistantExecutionTarget.singleAgent) { - final target = currentAssistantExecutionTarget; - final nextProfile = gatewayProfileForAssistantExecutionTargetInternal( - target, - ).copyWith(selectedAgentId: agentsControllerInternal.selectedAgentId); - await AppControllerDesktopSettings(this).saveSettings( - settings.copyWithGatewayProfileAt( - gatewayProfileIndexForExecutionTargetInternal(target), - nextProfile, - ), - refreshAfterSave: false, - ); - } + final target = currentAssistantExecutionTarget; + final nextProfile = gatewayProfileForAssistantExecutionTargetInternal( + target, + ).copyWith(selectedAgentId: agentsControllerInternal.selectedAgentId); + await AppControllerDesktopSettings(this).saveSettings( + settings.copyWithGatewayProfileAt( + gatewayProfileIndexForExecutionTargetInternal(target), + nextProfile, + ), + refreshAfterSave: false, + ); sessionsControllerInternal.configure( mainSessionKey: runtimeInternal.snapshot.mainSessionKey ?? 'main', selectedAgentId: agentsControllerInternal.selectedAgentId, @@ -205,9 +200,7 @@ extension AppControllerDesktopThreadActions on AppController { final nextTarget = assistantExecutionTargetForSession(nextSessionKey); final nextViewMode = assistantMessageViewModeForSession(nextSessionKey); - if (!isSingleAgentMode) { - preserveGatewayHistoryForSessionInternal(previousSessionKey); - } + preserveGatewayHistoryForSessionInternal(previousSessionKey); await setCurrentAssistantSessionKeyInternal(nextSessionKey); upsertTaskThreadInternal( @@ -226,9 +219,6 @@ extension AppControllerDesktopThreadActions on AppController { persistDefaultSelection: false, preserveGatewayHistoryForSelectedThread: false, ); - if (nextTarget == AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession(nextSessionKey); - } recomputeTasksInternal(); } @@ -267,17 +257,6 @@ extension AppControllerDesktopThreadActions on AppController { recomputeTasksInternal(); throw error; } - if (currentTarget == AssistantExecutionTarget.singleAgent) { - await sendSingleAgentMessageInternal( - message, - thinking: thinking, - attachments: attachments, - localAttachments: localAttachments, - ); - await flushAssistantThreadPersistenceInternal(); - recomputeTasksInternal(); - return; - } await enqueueThreadTurnInternal( normalizedAssistantSessionKeyInternal(currentSessionKey), () async { @@ -456,32 +435,6 @@ extension AppControllerDesktopThreadActions on AppController { notifyIfActiveInternal(); return; } - if (isSingleAgentMode) { - final sessionKey = normalizedAssistantSessionKeyInternal( - sessionsControllerInternal.currentSessionKey, - ); - if (aiGatewayPendingSessionKeysInternal.contains(sessionKey)) { - await goTaskServiceClientInternal.cancelTask( - route: GoTaskServiceRoute.externalAcpSingle, - target: AssistantExecutionTarget.singleAgent, - sessionId: sessionKey, - threadId: sessionKey, - ); - aiGatewayPendingSessionKeysInternal.remove(sessionKey); - clearAiGatewayStreamingTextInternal(sessionKey); - upsertTaskThreadInternal( - sessionKey, - lifecycleStatus: 'ready', - lastRunAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - lastResultCode: 'aborted', - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - recomputeTasksInternal(); - notifyIfActiveInternal(); - return; - } - return; - } final sessionKey = normalizedAssistantSessionKeyInternal( sessionsControllerInternal.currentSessionKey, ); diff --git a/lib/app/app_controller_desktop_thread_binding.dart b/lib/app/app_controller_desktop_thread_binding.dart index 578288d2..6bf0f069 100644 --- a/lib/app/app_controller_desktop_thread_binding.dart +++ b/lib/app/app_controller_desktop_thread_binding.dart @@ -36,7 +36,6 @@ import 'app_controller_desktop_core.dart'; import 'app_controller_desktop_navigation.dart'; import 'app_controller_desktop_gateway.dart'; import 'app_controller_desktop_settings.dart'; -import 'app_controller_desktop_single_agent.dart'; import 'app_controller_desktop_thread_sessions.dart'; import 'app_controller_desktop_thread_actions.dart'; import 'app_controller_desktop_workspace_execution.dart'; @@ -48,12 +47,10 @@ import 'app_controller_desktop_runtime_helpers.dart'; class DesktopThreadBindingSnapshotInternal { const DesktopThreadBindingSnapshotInternal({ required this.executionTarget, - required this.selectedSingleAgentProvider, required this.record, }); final AssistantExecutionTarget executionTarget; - final SingleAgentProvider selectedSingleAgentProvider; final TaskThread? record; } @@ -70,12 +67,8 @@ resolveDesktopThreadBindingSnapshotInternal({ : assistantExecutionTargetFromExecutionMode( latestRecord.executionBinding.executionMode, )); - final selectedProvider = SingleAgentProviderCopy.fromJsonValue( - latestRecord?.executionBinding.providerId ?? '', - ); return DesktopThreadBindingSnapshotInternal( executionTarget: resolvedExecutionTarget, - selectedSingleAgentProvider: selectedProvider, record: latestRecord, ); } @@ -196,33 +189,6 @@ extension AppControllerDesktopThreadBinding on AppController { required ThreadOwnerScope ownerScope, WorkspaceBinding? existingBinding, }) { - if (executionTarget == AssistantExecutionTarget.singleAgent) { - if (existingBinding != null && - existingBinding.workspaceKind == WorkspaceKind.localFs) { - final existingPath = existingBinding.workspacePath.trim(); - if (existingPath.isNotEmpty && - ensureLocalWorkspaceDirectoryInternal(existingPath)) { - // A task thread owns one stable local workingDirectory for its - // lifetime. Do not silently rebind it after the initial allocation. - return existingBinding.copyWith( - displayPath: existingBinding.workspacePath, - ); - } - } - final localPath = localThreadWorkspacePathInternal(sessionKey); - if (localPath.isEmpty) { - throw StateError( - 'Local executable thread $sessionKey requires a writable local workspace.', - ); - } - return WorkspaceBinding( - workspaceId: normalizedAssistantSessionKeyInternal(sessionKey), - workspaceKind: WorkspaceKind.localFs, - workspacePath: localPath, - displayPath: localPath, - writable: true, - ); - } final remotePath = remoteThreadWorkspacePathInternal( sessionKey, ownerScope, @@ -251,34 +217,21 @@ extension AppControllerDesktopThreadBinding on AppController { ExecutionBinding buildDesktopExecutionBindingInternal({ required AssistantExecutionTarget executionTarget, - required SingleAgentProvider singleAgentProvider, ExecutionBinding? existingBinding, }) { - final selectedProviderId = - executionTarget == AssistantExecutionTarget.singleAgent - ? settings - .sanitizeSingleAgentProviderSelection(singleAgentProvider) - .providerId - : kCanonicalGatewayProviderId; + const selectedProviderId = kCanonicalGatewayProviderId; return (existingBinding ?? ExecutionBinding( - executionMode: ThreadExecutionMode.localAgent, + executionMode: ThreadExecutionMode.gateway, executorId: selectedProviderId, providerId: selectedProviderId, endpointId: '', )) .copyWith( - executionMode: switch (executionTarget) { - AssistantExecutionTarget.singleAgent => - ThreadExecutionMode.localAgent, - AssistantExecutionTarget.gateway => ThreadExecutionMode.gateway, - }, + executionMode: ThreadExecutionMode.gateway, executorId: selectedProviderId, providerId: selectedProviderId, - providerSource: - executionTarget == AssistantExecutionTarget.singleAgent - ? existingBinding?.providerSource - : ThreadSelectionSource.inherited, + providerSource: ThreadSelectionSource.inherited, ); } @@ -310,7 +263,6 @@ extension AppControllerDesktopThreadBinding on AppController { workspaceBinding: workspaceBinding, executionBinding: buildDesktopExecutionBindingInternal( executionTarget: snapshot.executionTarget, - singleAgentProvider: snapshot.selectedSingleAgentProvider, existingBinding: snapshot.record?.executionBinding, ), lifecycleState: diff --git a/lib/app/app_controller_desktop_thread_sessions.dart b/lib/app/app_controller_desktop_thread_sessions.dart index 89a0fb0a..980587a2 100644 --- a/lib/app/app_controller_desktop_thread_sessions.dart +++ b/lib/app/app_controller_desktop_thread_sessions.dart @@ -37,7 +37,6 @@ import 'app_controller_desktop_navigation.dart'; import 'app_controller_desktop_gateway.dart'; import 'app_controller_desktop_settings.dart'; import 'app_controller_desktop_single_agent.dart'; -import 'app_controller_desktop_single_agent_status_messages.dart'; import 'app_controller_desktop_thread_binding.dart'; import 'app_controller_desktop_thread_actions.dart'; import 'app_controller_desktop_workspace_execution.dart'; @@ -109,13 +108,6 @@ extension AppControllerDesktopThreadSessions on AppController { } int assistantSkillCountForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - final target = assistantExecutionTargetForSession(normalizedSessionKey); - if (target == AssistantExecutionTarget.singleAgent) { - return assistantImportedSkillsForSession(normalizedSessionKey).length; - } return skills.length; } @@ -153,18 +145,6 @@ extension AppControllerDesktopThreadSessions on AppController { final normalizedSessionKey = normalizedAssistantSessionKeyInternal( sessionKey, ); - final target = assistantExecutionTargetForSession(normalizedSessionKey); - final latestResolvedModel = - taskThreadForSessionInternal( - normalizedSessionKey, - )?.latestResolvedRuntimeModel.trim() ?? - ''; - if (target == AssistantExecutionTarget.singleAgent) { - if (latestResolvedModel.isNotEmpty) { - return latestResolvedModel; - } - return singleAgentRuntimeModelForSession(normalizedSessionKey); - } final recordModel = assistantThreadRecordsInternal[normalizedSessionKey]?.assistantModelId .trim() ?? @@ -176,7 +156,9 @@ extension AppControllerDesktopThreadSessions on AppController { (availableChoices.isEmpty || availableChoices.contains(recordModel))) { return recordModel; } - return resolvedAssistantModelForTargetInternal(target); + return resolvedAssistantModelForTargetInternal( + AssistantExecutionTarget.gateway, + ); } String assistantWorkspacePathForSession(String sessionKey) { @@ -194,7 +176,7 @@ extension AppControllerDesktopThreadSessions on AppController { normalizedAssistantSessionKeyInternal(sessionKey), ); if (record == null) { - return WorkspaceRefKind.localPath; + return WorkspaceRefKind.remotePath; } return record.workspaceBinding.workspaceKind == WorkspaceKind.localFs ? WorkspaceRefKind.localPath @@ -237,177 +219,8 @@ extension AppControllerDesktopThreadSessions on AppController { ); } - SingleAgentProvider singleAgentProviderForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - final selectedProvider = SingleAgentProviderCopy.fromJsonValue( - taskThreadForSessionInternal( - normalizedSessionKey, - )?.executionBinding.providerId ?? - '', - ); - if (!selectedProvider.isUnspecified) { - return selectedProvider; - } - final options = singleAgentProviderOptions; - return options.isEmpty ? SingleAgentProvider.unspecified : options.first; - } - - SingleAgentProvider get currentSingleAgentProvider => - singleAgentProviderForSession(currentSessionKey); - - SingleAgentProvider? singleAgentResolvedProviderForSession( - String sessionKey, - ) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - final record = taskThreadForSessionInternal(normalizedSessionKey); - final resolvedProviderId = record?.latestResolvedProviderId.trim() ?? ''; - if (resolvedProviderId.isNotEmpty) { - return bridgeProviderForId(resolvedProviderId) ?? - SingleAgentProviderCopy.fromJsonValue(resolvedProviderId); - } - return null; - } - - SingleAgentProvider? get currentSingleAgentResolvedProvider => - singleAgentResolvedProviderForSession(currentSessionKey); - - SingleAgentProvider? singleAgentCatalogProviderForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - final selection = singleAgentProviderForSession(normalizedSessionKey); - if (selection.isUnspecified) { - return null; - } - return bridgeProviderForId(selection.providerId); - } - - SingleAgentProvider? get currentSingleAgentCatalogProvider => - singleAgentCatalogProviderForSession(currentSessionKey); - - bool singleAgentNeedsBridgeProviderForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - if (assistantExecutionTargetForSession(normalizedSessionKey) != - AssistantExecutionTarget.singleAgent) { - return false; - } - if (resolveExternalAcpEndpointForTargetInternal( - AssistantExecutionTarget.singleAgent, - ) == - null) { - return false; - } - return bridgeProviderCatalog.isEmpty; - } - - bool get currentSingleAgentNeedsBridgeProvider => - singleAgentNeedsBridgeProviderForSession(currentSessionKey); - - bool singleAgentShouldSuggestAcpSwitchForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - if (assistantExecutionTargetForSession(normalizedSessionKey) != - AssistantExecutionTarget.singleAgent) { - return false; - } - if (resolveExternalAcpEndpointForTargetInternal( - AssistantExecutionTarget.singleAgent, - ) == - null) { - return false; - } - final selection = singleAgentProviderForSession(normalizedSessionKey); - if (selection.isUnspecified) { - return false; - } - final selectedProvider = bridgeProviderForId(selection.providerId); - return selectedProvider == null && bridgeProviderCatalog.isNotEmpty; - } - - bool get currentSingleAgentShouldSuggestAcpSwitch => - singleAgentShouldSuggestAcpSwitchForSession(currentSessionKey); - - String singleAgentRuntimeModelForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - return taskThreadForSessionInternal( - normalizedSessionKey, - )?.latestResolvedRuntimeModel.trim() ?? - ''; - } - - String get currentSingleAgentRuntimeModel => - singleAgentRuntimeModelForSession(currentSessionKey); - - String singleAgentModelDisplayLabelForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - final runtimeModel = singleAgentRuntimeModelForSession( - normalizedSessionKey, - ); - if (runtimeModel.isNotEmpty) { - return runtimeModel; - } - final model = assistantModelForSession(normalizedSessionKey); - if (model.isNotEmpty) { - return model; - } - final provider = - singleAgentResolvedProviderForSession(normalizedSessionKey) ?? - singleAgentCatalogProviderForSession(normalizedSessionKey) ?? - singleAgentProviderForSession(normalizedSessionKey); - return appText( - '请先配置 ${provider.label} 模型', - 'Configure ${provider.label} model', - ); - } - - String get currentSingleAgentModelDisplayLabel => - singleAgentModelDisplayLabelForSession(currentSessionKey); - - bool singleAgentShouldShowModelControlForSession(String sessionKey) { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - if (assistantExecutionTargetForSession(normalizedSessionKey) != - AssistantExecutionTarget.singleAgent) { - return true; - } - return singleAgentRuntimeModelForSession(normalizedSessionKey).isNotEmpty; - } - - bool get currentSingleAgentShouldShowModelControl => - singleAgentShouldShowModelControlForSession(currentSessionKey); - - List get singleAgentProviderOptions => - bridgeProviderCatalog; - String get assistantConversationOwnerLabel { - if (!isSingleAgentMode) { - return activeAgentName; - } - final resolvedProvider = currentSingleAgentResolvedProvider; - if (resolvedProvider != null) { - return resolvedProvider.label; - } - final catalogProvider = currentSingleAgentCatalogProvider; - if (catalogProvider != null) { - return catalogProvider.label; - } - final provider = currentSingleAgentProvider; - if (!provider.isUnspecified) { - return provider.label; - } - return appText('单机智能体', 'Single Agent'); + return activeAgentName; } AssistantThreadConnectionState get currentAssistantConnectionState => @@ -420,50 +233,6 @@ extension AppControllerDesktopThreadSessions on AppController { sessionKey, ); final target = assistantExecutionTargetForSession(normalizedSessionKey); - if (target == AssistantExecutionTarget.singleAgent) { - final primaryLabel = appText('Bridge', 'Bridge'); - final provider = singleAgentProviderForSession(normalizedSessionKey); - final resolvedProvider = singleAgentResolvedProviderForSession( - normalizedSessionKey, - ); - final catalogProvider = singleAgentCatalogProviderForSession( - normalizedSessionKey, - ); - final model = assistantModelForSession(normalizedSessionKey); - final providerReady = catalogProvider != null; - final displayProvider = resolvedProvider ?? catalogProvider ?? provider; - final detail = providerReady - ? joinConnectionPartsInternal([displayProvider.label, model]) - : singleAgentShouldSuggestAcpSwitchForSession(normalizedSessionKey) - ? appText( - '${provider.label} 当前不可用,请改成 Bridge 当前可用的 Provider。', - '${provider.label} is unavailable. Switch to a provider currently advertised by the bridge.', - ) - : singleAgentNeedsBridgeProviderForSession(normalizedSessionKey) - ? appText( - 'Bridge 当前没有可用 Provider。', - 'The bridge does not currently advertise any available providers.', - ) - : appText( - '当前线程的 Bridge Provider 尚未就绪。', - 'The bridge provider for this thread is not ready yet.', - ); - return AssistantThreadConnectionState( - executionTarget: target, - status: providerReady - ? RuntimeConnectionStatus.connected - : RuntimeConnectionStatus.offline, - primaryLabel: primaryLabel, - detailLabel: detail.isEmpty - ? appText('未配置单机智能体', 'Single Agent is not configured') - : detail, - ready: providerReady, - pairingRequired: false, - gatewayTokenMissing: false, - lastError: null, - ); - } - return resolveGatewayThreadConnectionStateInternal( target: target, connection: connection, @@ -534,14 +303,8 @@ extension AppControllerDesktopThreadSessions on AppController { final sessionKey = normalizedAssistantSessionKeyInternal( sessionsControllerInternal.currentSessionKey, ); - final items = List.from( - isSingleAgentMode - ? const [] - : chatControllerInternal.messages, - ); - final threadItems = isSingleAgentMode - ? assistantThreadMessagesInternal[sessionKey] - : null; + final items = List.from(chatControllerInternal.messages); + final threadItems = assistantThreadMessagesInternal[sessionKey]; if (threadItems != null && threadItems.isNotEmpty) { items.addAll(threadItems); } @@ -549,9 +312,7 @@ extension AppControllerDesktopThreadSessions on AppController { if (localItems != null && localItems.isNotEmpty) { items.addAll(localItems); } - final streaming = isSingleAgentMode - ? (aiGatewayStreamingTextBySessionInternal[sessionKey]?.trim() ?? '') - : (chatControllerInternal.streamingAssistantText?.trim() ?? ''); + final streaming = chatControllerInternal.streamingAssistantText?.trim() ?? ''; if (streaming.isNotEmpty) { items.add( GatewayChatMessage( @@ -604,12 +365,7 @@ extension AppControllerDesktopThreadSessions on AppController { WorkspaceRefKind defaultWorkspaceRefKindForTargetInternal( AssistantExecutionTarget target, - ) { - return switch (target) { - AssistantExecutionTarget.singleAgent => WorkspaceRefKind.localPath, - AssistantExecutionTarget.gateway => WorkspaceRefKind.remotePath, - }; - } + ) => WorkspaceRefKind.remotePath; List assistantSessionsInternal() { final byKey = {}; @@ -663,7 +419,7 @@ AssistantExecutionTarget resolveAssistantExecutionTargetFromRecordsForTest( }) { final record = primaryRecord ?? fallbackRecord; return record == null - ? AssistantExecutionTarget.singleAgent + ? AssistantExecutionTarget.gateway : assistantExecutionTargetFromExecutionMode( record.executionBinding.executionMode, ); diff --git a/lib/app/app_controller_desktop_thread_sessions_collaboration_impl.dart b/lib/app/app_controller_desktop_thread_sessions_collaboration_impl.dart index 6466bcc0..8df7bda7 100644 --- a/lib/app/app_controller_desktop_thread_sessions_collaboration_impl.dart +++ b/lib/app/app_controller_desktop_thread_sessions_collaboration_impl.dart @@ -346,21 +346,6 @@ List assistantModelChoicesForSessionThreadSessionInternal( AppController controller, String sessionKey, ) { - final normalizedSessionKey = normalizeAssistantSessionKeyThreadInternal( - sessionKey, - ); - final target = controller.assistantExecutionTargetForSession( - normalizedSessionKey, - ); - if (target == AssistantExecutionTarget.singleAgent) { - final runtimeModel = controller.singleAgentRuntimeModelForSession( - normalizedSessionKey, - ); - if (runtimeModel.isNotEmpty) { - return [runtimeModel]; - } - return const []; - } final runtimeModels = connectedGatewayModelChoicesThreadSessionInternal( controller, ); @@ -402,9 +387,6 @@ String resolvedDefaultModelThreadSessionInternal(AppController controller) { bool canQuickConnectGatewayThreadSessionInternal(AppController controller) { final target = controller.currentAssistantExecutionTarget; - if (target == AssistantExecutionTarget.singleAgent) { - return false; - } final profile = controller.gatewayProfileForAssistantExecutionTargetInternal( target, ); @@ -418,12 +400,7 @@ bool canQuickConnectGatewayThreadSessionInternal(AppController controller) { if (profile.mode == RuntimeConnectionMode.local) { return true; } - final defaults = switch (target) { - AssistantExecutionTarget.singleAgent => GatewayConnectionProfile.emptySlot( - index: kGatewayRemoteProfileIndex, - ), - AssistantExecutionTarget.gateway => GatewayConnectionProfile.defaults(), - }; + final defaults = GatewayConnectionProfile.defaults(); return controller.hasStoredGatewayCredential || host != defaults.host || profile.port != defaults.port || diff --git a/lib/app/app_controller_desktop_thread_storage.dart b/lib/app/app_controller_desktop_thread_storage.dart index 73235f25..5c9225b6 100644 --- a/lib/app/app_controller_desktop_thread_storage.dart +++ b/lib/app/app_controller_desktop_thread_storage.dart @@ -62,10 +62,7 @@ extension AppControllerDesktopThreadStorage on AppController { } Future ensureActiveAssistantThreadInternal() async { - if (!isSingleAgentMode || - !isAssistantTaskArchived( - sessionsControllerInternal.currentSessionKey, - )) { + if (!isAssistantTaskArchived(sessionsControllerInternal.currentSessionKey)) { return; } final fallback = assistantSessionSummariesInternal().firstWhere( @@ -219,14 +216,9 @@ extension AppControllerDesktopThreadStorage on AppController { AssistantExecutionTarget sanitizeExecutionTargetInternal( AssistantExecutionTarget? target, - ) { - final sanitized = featuresFor( - hostUiFeaturePlatformInternal, - ).sanitizeExecutionTarget(target); - return sanitized == AssistantExecutionTarget.singleAgent - ? AssistantExecutionTarget.singleAgent - : AssistantExecutionTarget.gateway; - } + ) => featuresFor( + hostUiFeaturePlatformInternal, + ).sanitizeExecutionTarget(target); AssistantExecutionTarget sanitizePersistedExecutionTargetInternal( AssistantExecutionTarget? target, @@ -691,16 +683,11 @@ extension AppControllerDesktopThreadStorage on AppController { record.executionBinding.executionMode, ), ); - final recordProvider = - recordExecutionTarget == AssistantExecutionTarget.singleAgent - ? SingleAgentProviderCopy.fromJsonValue( - record.executionBinding.providerId, - ) - : const SingleAgentProvider( - providerId: kCanonicalGatewayProviderId, - label: kCanonicalGatewayProviderLabel, - badge: 'OC', - ); + const recordProvider = SingleAgentProvider( + providerId: kCanonicalGatewayProviderId, + label: kCanonicalGatewayProviderLabel, + badge: 'OC', + ); final workspaceBinding = record.workspaceBinding.copyWith( workspaceId: sessionKey, displayPath: record.workspaceKind == WorkspaceKind.localFs @@ -732,10 +719,7 @@ extension AppControllerDesktopThreadStorage on AppController { ), executorId: recordProvider.providerId, providerId: recordProvider.providerId, - providerSource: - recordExecutionTarget == AssistantExecutionTarget.singleAgent - ? record.executionBinding.providerSource - : ThreadSelectionSource.inherited, + providerSource: ThreadSelectionSource.inherited, ), lifecycleState: record.lifecycleState.copyWith(status: 'ready'), ); diff --git a/lib/app/app_controller_desktop_workspace_execution.dart b/lib/app/app_controller_desktop_workspace_execution.dart index 4492689e..1b2628a7 100644 --- a/lib/app/app_controller_desktop_workspace_execution.dart +++ b/lib/app/app_controller_desktop_workspace_execution.dart @@ -36,7 +36,6 @@ import 'app_controller_desktop_core.dart'; import 'app_controller_desktop_navigation.dart'; import 'app_controller_desktop_gateway.dart'; import 'app_controller_desktop_settings.dart'; -import 'app_controller_desktop_single_agent.dart'; import 'app_controller_desktop_thread_binding.dart'; import 'app_controller_desktop_thread_sessions.dart'; import 'app_controller_desktop_thread_actions.dart'; @@ -65,7 +64,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { sessionsControllerInternal.currentSessionKey, executionTarget: resolvedTarget, messageViewMode: currentAssistantMessageViewMode, - singleAgentProvider: currentSingleAgentProvider, ); } StateError? bindingError; @@ -96,11 +94,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { sessionKey: sessionsControllerInternal.currentSessionKey, persistDefaultSelection: true, ); - if (resolvedTarget == AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession( - sessionsControllerInternal.currentSessionKey, - ); - } if (bindingError != null) { debugPrint('setAssistantExecutionTarget binding fallback: $bindingError'); } @@ -108,43 +101,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { notifyIfActiveInternal(); } - Future setSingleAgentProvider(SingleAgentProvider provider) async { - final sessionKey = normalizedAssistantSessionKeyInternal(currentSessionKey); - final sanitizedProvider = settings.sanitizeSingleAgentProviderSelection( - provider, - ); - if (singleAgentProviderForSession(sessionKey) == sanitizedProvider) { - return; - } - if (!assistantThreadRecordsInternal.containsKey(sessionKey)) { - initializeAssistantThreadContext( - sessionKey, - executionTarget: assistantExecutionTargetForSession(sessionKey), - messageViewMode: assistantMessageViewModeForSession(sessionKey), - singleAgentProvider: currentSingleAgentProvider, - ); - } - upsertTaskThreadInternal( - sessionKey, - singleAgentProvider: sanitizedProvider, - singleAgentProviderSource: ThreadSelectionSource.explicit, - latestResolvedRuntimeModel: '', - latestResolvedProviderId: '', - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - recomputeTasksInternal(); - notifyIfActiveInternal(); - if (assistantExecutionTargetForSession(sessionKey) == - AssistantExecutionTarget.singleAgent) { - await refreshSingleAgentSkillsForSession(sessionKey); - } - unawaited( - refreshMultiAgentMounts( - sync: settings.multiAgent.autoSync, - ).catchError((_) {}), - ); - } - Future setAssistantMessageViewMode( AssistantMessageViewMode mode, ) async { @@ -159,7 +115,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { sessionKey, executionTarget: assistantExecutionTargetForSession(sessionKey), messageViewMode: assistantMessageViewModeForSession(sessionKey), - singleAgentProvider: singleAgentProviderForSession(sessionKey), ); } upsertTaskThreadInternal( @@ -194,14 +149,12 @@ extension AppControllerDesktopWorkspaceExecution on AppController { final normalizedSessionKey = normalizedAssistantSessionKeyInternal( sessionKey, ); - if (resolvedTarget != AssistantExecutionTarget.singleAgent) { - upsertTaskThreadInternal( - normalizedSessionKey, - latestResolvedRuntimeModel: '', - latestResolvedProviderId: '', - updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), - ); - } + upsertTaskThreadInternal( + normalizedSessionKey, + latestResolvedRuntimeModel: '', + latestResolvedProviderId: '', + updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), + ); if (!matchesSessionKey( normalizedSessionKey, sessionsControllerInternal.currentSessionKey, @@ -216,26 +169,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { ); } - if (resolvedTarget == AssistantExecutionTarget.singleAgent) { - if (preserveGatewayHistoryForSelectedThread && - runtimeInternal.isConnected) { - preserveGatewayHistoryForSessionInternal(normalizedSessionKey); - } - await ensureActiveAssistantThreadInternal(); - if (runtimeInternal.isConnected) { - try { - await AppControllerDesktopGateway(this).disconnectGateway(); - } catch (_) { - // Preserve the selected thread-bound target even when the active - // gateway session does not close cleanly on the first attempt. - } - } else { - chatControllerInternal.clear(); - } - await setCurrentAssistantSessionKeyInternal(normalizedSessionKey); - return; - } - final targetProfile = gatewayProfileForAssistantExecutionTargetInternal( resolvedTarget, ); @@ -300,9 +233,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { messageViewMode: assistantMessageViewModeForSession( normalizedSessionKey, ), - singleAgentProvider: singleAgentProviderForSession( - normalizedSessionKey, - ), ); } upsertTaskThreadInternal( @@ -328,7 +258,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { String title = '', AssistantExecutionTarget? executionTarget, AssistantMessageViewMode? messageViewMode, - SingleAgentProvider? singleAgentProvider, }) { final normalizedSessionKey = normalizedAssistantSessionKeyInternal( sessionKey, @@ -361,17 +290,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { messageViewMode: messageViewMode ?? assistantMessageViewModeForSession(currentSessionKey), - singleAgentProvider: - singleAgentProvider ?? - settings.sanitizeSingleAgentProviderSelection( - SingleAgentProviderCopy.fromJsonValue( - assistantThreadRecordsInternal[normalizedSessionKey] - ?.executionBinding - .providerId ?? - '', - ), - ), - singleAgentProviderSource: ThreadSelectionSource.inherited, updatedAtMs: DateTime.now().millisecondsSinceEpoch.toDouble(), ); // Re-read the current thread target when the async binding sync runs so a @@ -382,30 +300,6 @@ extension AppControllerDesktopWorkspaceExecution on AppController { notifyIfActiveInternal(); } - Future refreshSingleAgentSkillsForSession(String sessionKey) async { - final normalizedSessionKey = normalizedAssistantSessionKeyInternal( - sessionKey, - ); - if (assistantExecutionTargetForSession(normalizedSessionKey) != - AssistantExecutionTarget.singleAgent) { - return; - } - final localSkills = await singleAgentLocalSkillsForSessionInternal( - normalizedSessionKey, - ); - await replaceSingleAgentThreadSkillsInternal( - normalizedSessionKey, - localSkills, - ); - } - - Future refreshSingleAgentLocalSkillsForSession( - String sessionKey, - ) async { - await refreshSharedSingleAgentLocalSkillsCacheInternal(forceRescan: true); - await refreshSingleAgentSkillsForSession(sessionKey); - } - Future toggleAssistantSkillForSession( String sessionKey, String skillKey, diff --git a/lib/app/app_shell_desktop.dart b/lib/app/app_shell_desktop.dart index 9b833bb0..d7724930 100644 --- a/lib/app/app_shell_desktop.dart +++ b/lib/app/app_shell_desktop.dart @@ -94,7 +94,6 @@ class _AppShellState extends State { title: appText('新对话', 'New conversation'), executionTarget: target, messageViewMode: controller.currentAssistantMessageViewMode, - singleAgentProvider: SingleAgentProvider.unspecified, ); controller.navigateTo(WorkspaceDestination.assistant); await controller.switchSession(sessionKey); diff --git a/lib/app/ui_feature_manifest_core.dart b/lib/app/ui_feature_manifest_core.dart index 2de24199..e56f2e0c 100644 --- a/lib/app/ui_feature_manifest_core.dart +++ b/lib/app/ui_feature_manifest_core.dart @@ -520,38 +520,16 @@ class UiFeatureAccess { } List get availableExecutionTargets { - final targets = []; - if (supportsDirectAi) { - targets.add(AssistantExecutionTarget.singleAgent); - } if (supportsRelayGateway) { - targets.add(AssistantExecutionTarget.gateway); + return const [AssistantExecutionTarget.gateway]; } - return targets; + return const [AssistantExecutionTarget.gateway]; } AssistantExecutionTarget sanitizeExecutionTarget( AssistantExecutionTarget? target, ) { - final available = availableExecutionTargets; - if (target != null && available.contains(target)) { - return target; - } - final preferredOrder = platform == UiFeaturePlatform.web - ? const [ - AssistantExecutionTarget.singleAgent, - AssistantExecutionTarget.gateway, - ] - : const [ - AssistantExecutionTarget.singleAgent, - AssistantExecutionTarget.gateway, - ]; - for (final candidate in preferredOrder) { - if (available.contains(candidate)) { - return candidate; - } - } - return AssistantExecutionTarget.singleAgent; + return AssistantExecutionTarget.gateway; } } diff --git a/lib/features/assistant/assistant_page_components.dart b/lib/features/assistant/assistant_page_components.dart index e273660b..ae3b9933 100644 --- a/lib/features/assistant/assistant_page_components.dart +++ b/lib/features/assistant/assistant_page_components.dart @@ -82,10 +82,7 @@ class AssistantTaskRailStateInternal extends State { final groupedTasks = groupTasksForRailInternal( tasks, widget.controller.visibleAssistantExecutionTargets( - const [ - AssistantExecutionTarget.singleAgent, - AssistantExecutionTarget.gateway, - ], + const [AssistantExecutionTarget.gateway], ), ); final runningCount = tasks @@ -501,55 +498,14 @@ class AssistantEmptyStateInternal extends StatelessWidget { Widget build(BuildContext context) { final theme = Theme.of(context); final connectionState = controller.currentAssistantConnectionState; - final singleAgent = connectionState.isSingleAgent; final connected = connectionState.connected; - final singleAgentNeedsBridgeProvider = - controller.currentSingleAgentNeedsBridgeProvider; - final singleAgentSuggestsAcpSwitch = - controller.currentSingleAgentShouldSuggestAcpSwitch; - final providerLabel = - (controller.currentSingleAgentResolvedProvider ?? - controller.currentSingleAgentProvider) - .label; final reconnectAvailable = controller.canQuickConnectGateway; - final title = singleAgent - ? connected - ? appText('开始智能体任务', 'Start an agent task') - : singleAgentNeedsBridgeProvider - ? appText( - '等待 Bridge Provider', - 'Waiting for a bridge provider', - ) - : appText( - '等待 Bridge 就绪', - 'Waiting for bridge readiness', - ) - : connected + final title = connected ? appText('开始对话或运行任务', 'Start a chat or run a task') : connectionState.status == RuntimeConnectionStatus.error ? appText('Bridge 连接失败', 'Bridge connection failed') : appText('先连接 Bridge', 'Connect xworkmate-bridge first'); - final description = singleAgent - ? connected - ? appText( - '当前线程会通过 Bridge 当前广告的 Provider 处理任务,不会建立 OpenClaw Gateway 会话。', - 'This thread runs through the provider currently advertised by the bridge and does not open an OpenClaw Gateway session.', - ) - : singleAgentSuggestsAcpSwitch - ? appText( - '当前线程固定为 $providerLabel,但它在这台设备上不可用。请改成 Bridge 当前可用的 Provider。', - 'This thread is pinned to $providerLabel, but it is unavailable on this device. Switch to a provider currently advertised by the bridge.', - ) - : singleAgentNeedsBridgeProvider - ? appText( - 'Bridge 当前没有广告可用 Provider。恢复后可直接开始任务;当前流程不依赖本地集成配置。', - 'The bridge is not advertising any available providers right now. Once it recovers, this thread can start directly without extra local integration setup.', - ) - : appText( - '当前线程的 Bridge Provider 尚未就绪。请等待 Bridge 恢复,或切换到当前可用 Provider。', - 'The bridge provider for this thread is not ready yet. Wait for the bridge to recover, or switch to a currently available provider.', - ) - : connected + final description = connected ? appText( '输入需求后即可开始执行,结果会回到当前会话并同步到任务页。', 'Type a request to start execution. Results return to this session and the Tasks page.', @@ -604,8 +560,6 @@ class AssistantEmptyStateInternal extends StatelessWidget { children: [ FilledButton.icon( onPressed: connected - ? onFocusComposer - : singleAgent ? onFocusComposer : reconnectAvailable ? () async { @@ -615,8 +569,6 @@ class AssistantEmptyStateInternal extends StatelessWidget { icon: Icon( connected ? Icons.edit_rounded - : singleAgent - ? Icons.smart_toy_outlined : reconnectAvailable ? Icons.refresh_rounded : Icons.link_rounded, @@ -624,8 +576,6 @@ class AssistantEmptyStateInternal extends StatelessWidget { label: Text( connected ? appText('开始输入', 'Start typing') - : singleAgent - ? appText('查看线程工具栏', 'Open toolbar') : reconnectAvailable ? appText('重新连接 Bridge', 'Reconnect bridge') : appText( diff --git a/lib/features/assistant/assistant_page_composer_bar.dart b/lib/features/assistant/assistant_page_composer_bar.dart index a69bbf53..9ebf5f88 100644 --- a/lib/features/assistant/assistant_page_composer_bar.dart +++ b/lib/features/assistant/assistant_page_composer_bar.dart @@ -118,7 +118,6 @@ class ComposerBarStateInternal extends State { late final TextEditingController skillPickerSearchControllerInternal; late final FocusNode skillPickerSearchFocusNodeInternal; bool handlingPasteShortcutInternal = false; - bool refreshingSingleAgentSkillsInternal = false; String skillPickerQueryInternal = ''; @override @@ -147,37 +146,8 @@ class ComposerBarStateInternal extends State { reportContentHeightInternal(); } - Future refreshSingleAgentSkillsInternal() async { - if (refreshingSingleAgentSkillsInternal) { - return; - } - setState(() { - refreshingSingleAgentSkillsInternal = true; - }); - try { - await widget.controller.refreshSingleAgentLocalSkillsForSession( - widget.controller.currentSessionKey, - ); - } finally { - if (mounted) { - setState(() { - refreshingSingleAgentSkillsInternal = false; - }); - } - } - } - - List activeSkillOptionsInternal() { - if (widget.controller.isSingleAgentMode) { - return widget.controller - .assistantImportedSkillsForSession( - widget.controller.currentSessionKey, - ) - .map(skillOptionFromThreadSkillInternal) - .toList(growable: false); - } - return widget.availableSkills; - } + List activeSkillOptionsInternal() => + widget.availableSkills; List filteredSkillOptionsInternal() { final normalizedQuery = skillPickerQueryInternal.trim().toLowerCase(); @@ -220,9 +190,6 @@ class ComposerBarStateInternal extends State { } skillPickerSearchFocusNodeInternal.requestFocus(); }); - if (widget.controller.isSingleAgentMode) { - unawaited(refreshSingleAgentSkillsInternal()); - } } @override @@ -350,7 +317,6 @@ class ComposerBarStateInternal extends State { resolveUiFeaturePlatformFromContext(context), ); final connectionState = controller.currentAssistantConnectionState; - final singleAgent = connectionState.isSingleAgent; final connected = connectionState.connected; final reconnectAvailable = controller.canQuickConnectGateway; final connecting = connectionState.connecting; @@ -374,12 +340,7 @@ class ComposerBarStateInternal extends State { final selectedSkills = widget.availableSkills .where((skill) => widget.selectedSkillKeys.contains(skill.key)) .toList(growable: false); - final displayedSingleAgentProvider = - controller.currentSingleAgentResolvedProvider ?? - controller.currentSingleAgentProvider; final submitLabel = connected - ? appText('提交', 'Submit') - : singleAgent ? appText('提交', 'Submit') : connecting ? appText('连接中…', 'Connecting…') @@ -432,12 +393,10 @@ class ComposerBarStateInternal extends State { tooltip: appText('任务对话模式', 'Task Dialog Mode'), onSelected: (value) { final resolvedTarget = - value == AssistantExecutionTarget.singleAgent - ? AssistantExecutionTarget.singleAgent - : resolveGatewayExecutionTargetFromVisibleTargets( - visibleExecutionTargets, - currentTarget: executionTarget, - ); + resolveGatewayExecutionTargetFromVisibleTargets( + visibleExecutionTargets, + currentTarget: executionTarget, + ); controller.setAssistantExecutionTarget(resolvedTarget); }, itemBuilder: (context) => compactExecutionTargets @@ -473,50 +432,7 @@ class ComposerBarStateInternal extends State { ), const SizedBox(width: 4), ], - if (singleAgent) ...[ - PopupMenuButton( - key: const Key('assistant-single-agent-provider-button'), - tooltip: appText('Bridge Provider', 'Bridge Provider'), - onSelected: (value) { - unawaited(controller.setSingleAgentProvider(value)); - }, - itemBuilder: (context) => controller - .singleAgentProviderOptions - .map( - (value) => PopupMenuItem( - value: value, - key: Key( - 'assistant-single-agent-provider-menu-item-${value.providerId}', - ), - child: Row( - children: [ - SingleAgentProviderBadgeInternal(provider: value), - const SizedBox(width: 10), - Expanded(child: Text(value.label)), - if (value == - controller.currentSingleAgentProvider) - const Icon(Icons.check_rounded, size: 18), - ], - ), - ), - ) - .toList(), - child: ComposerToolbarChipInternal( - leading: SingleAgentProviderBadgeInternal( - provider: displayedSingleAgentProvider, - ), - tooltip: singleAgentProviderTooltipInternal( - displayedSingleAgentProvider, - ), - showChevron: true, - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - ), - ), - const SizedBox(width: 4), - ] else ...[ + if (!connecting) ...[ PopupMenuButton( key: const Key('assistant-gateway-provider-button'), tooltip: appText('Gateway Provider', 'Gateway Provider'), @@ -795,8 +711,6 @@ class ComposerBarStateInternal extends State { ? null : connected ? widget.onSend - : singleAgent - ? widget.onSend : reconnectAvailable ? () async { await widget.onReconnectGateway(); @@ -817,8 +731,6 @@ class ComposerBarStateInternal extends State { children: [ Icon( connected - ? Icons.arrow_upward_rounded - : singleAgent ? Icons.arrow_upward_rounded : reconnectAvailable ? Icons.refresh_rounded diff --git a/lib/features/assistant/assistant_page_composer_state_helpers.dart b/lib/features/assistant/assistant_page_composer_state_helpers.dart index 31300e56..cfe42607 100644 --- a/lib/features/assistant/assistant_page_composer_state_helpers.dart +++ b/lib/features/assistant/assistant_page_composer_state_helpers.dart @@ -94,7 +94,7 @@ Widget buildSkillPickerOverlayForInternal( searchFocusNode: state.skillPickerSearchFocusNodeInternal, selectedSkillKeys: state.widget.selectedSkillKeys, filteredSkills: state.filteredSkillOptionsInternal(), - isLoading: state.refreshingSingleAgentSkillsInternal, + isLoading: false, hasQuery: state.skillPickerQueryInternal.trim().isNotEmpty, onQueryChanged: state.setSkillPickerQueryInternal, onToggleSkill: (skillKey) => state.widget.onToggleSkill(skillKey), diff --git a/lib/features/assistant/assistant_page_composer_support.dart b/lib/features/assistant/assistant_page_composer_support.dart index 611d8834..c87f3b9f 100644 --- a/lib/features/assistant/assistant_page_composer_support.dart +++ b/lib/features/assistant/assistant_page_composer_support.dart @@ -195,7 +195,6 @@ class ComposerToolbarChipStateInternal extension AssistantExecutionTargetIconInternal on AssistantExecutionTarget { IconData get icon => switch (this) { - AssistantExecutionTarget.singleAgent => Icons.hub_outlined, AssistantExecutionTarget.gateway => Icons.cloud_outlined, }; } diff --git a/lib/features/assistant/assistant_page_state_actions.dart b/lib/features/assistant/assistant_page_state_actions.dart index b1cdeea7..c5f5d018 100644 --- a/lib/features/assistant/assistant_page_state_actions.dart +++ b/lib/features/assistant/assistant_page_state_actions.dart @@ -87,11 +87,7 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { return; } - final shouldUseGatewayAgent = - executionTarget != AssistantExecutionTarget.singleAgent; - final autoAgent = shouldUseGatewayAgent - ? pickAutoAgentInternal(controller, rawPrompt) - : null; + final autoAgent = pickAutoAgentInternal(controller, rawPrompt); if (autoAgent != null) { await controller.selectAgent(autoAgent.id); } @@ -111,7 +107,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { attachmentNames: attachmentNames, selectedSkillLabels: selectedSkillLabels, executionTarget: executionTarget, - singleAgentProvider: controller.currentSingleAgentProvider, permissionLevel: settings.assistantPermissionLevel, ); @@ -127,7 +122,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { preview: rawPrompt, status: controller.hasAssistantPendingRun || - executionTarget == AssistantExecutionTarget.singleAgent || connectionState.connected ? 'running' : 'queued', @@ -256,12 +250,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { List availableSkillOptionsInternal( AppController controller, ) { - if (controller.isSingleAgentMode) { - return controller - .assistantImportedSkillsForSession(controller.currentSessionKey) - .map(skillOptionFromThreadSkillInternal) - .toList(growable: false); - } final options = []; final seenKeys = {}; @@ -306,7 +294,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { required List attachmentNames, required List selectedSkillLabels, required AssistantExecutionTarget executionTarget, - required SingleAgentProvider singleAgentProvider, required AssistantPermissionLevel permissionLevel, }) { final attachmentBlock = attachmentNames.isEmpty @@ -318,7 +305,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { final executionContext = 'Execution context:\n' '- target: ${executionTarget.promptValue}\n' - '${executionTarget == AssistantExecutionTarget.singleAgent ? '- provider: ${singleAgentProvider.providerId}\n' : ''}' '- permission: ${permissionLevel.promptValue}\n\n'; return switch (mode) { @@ -422,10 +408,7 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { final inheritedTarget = pickDraftThreadExecutionTargetInternal( currentTarget: widget.controller.currentAssistantExecutionTarget, visibleTargets: widget.controller.visibleAssistantExecutionTargets( - const [ - AssistantExecutionTarget.singleAgent, - AssistantExecutionTarget.gateway, - ], + const [AssistantExecutionTarget.gateway], ), localWorkspaceAvailable: widget.controller.settings.workspacePath .trim() @@ -456,7 +439,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { title: appText('新对话', 'New conversation'), executionTarget: inheritedTarget, messageViewMode: inheritedViewMode, - singleAgentProvider: widget.controller.currentSingleAgentProvider, ); await switchSessionWithRetryInternal(sessionKey); } @@ -534,7 +516,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { executionTarget: resolvedVisibleExecutionTargetInternal( widget.controller, supportedTargets: const [ - AssistantExecutionTarget.singleAgent, AssistantExecutionTarget.gateway, ], ), @@ -812,9 +793,6 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal { String buildDraftSessionKeyInternal(AppController controller) { final stamp = DateTime.now().millisecondsSinceEpoch; - if (controller.isSingleAgentMode) { - return 'draft:$stamp'; - } final selectedAgentId = controller.selectedAgentId.trim(); if (selectedAgentId.isEmpty) { return 'draft:$stamp'; diff --git a/lib/features/assistant/assistant_page_state_closure.dart b/lib/features/assistant/assistant_page_state_closure.dart index 6dc9615c..9610fab4 100644 --- a/lib/features/assistant/assistant_page_state_closure.dart +++ b/lib/features/assistant/assistant_page_state_closure.dart @@ -179,14 +179,9 @@ extension AssistantPageStateClosureInternal on AssistantPageStateInternal { inputController: inputControllerInternal, focusNode: composerFocusNodeInternal, thinkingLabel: thinkingLabelInternal, - showModelControl: - !controller.isSingleAgentMode - ? true - : controller.currentSingleAgentShouldShowModelControl, + showModelControl: true, modelLabel: - controller.isSingleAgentMode - ? controller.currentSingleAgentModelDisplayLabel - : controller.resolvedAssistantModel.isEmpty + controller.resolvedAssistantModel.isEmpty ? appText('未选择模型', 'No model selected') : controller.resolvedAssistantModel, modelOptions: controller.assistantModelChoices, diff --git a/lib/features/assistant/assistant_page_tooltip_labels.dart b/lib/features/assistant/assistant_page_tooltip_labels.dart index 6a55633e..f063349d 100644 --- a/lib/features/assistant/assistant_page_tooltip_labels.dart +++ b/lib/features/assistant/assistant_page_tooltip_labels.dart @@ -43,13 +43,6 @@ String executionTargetTooltipInternal(AssistantExecutionTarget target) => 'Task dialog mode: ${target.compactLabel}', ); -String singleAgentProviderTooltipInternal( - SingleAgentProvider provider, -) => appText( - 'Bridge Provider: ${provider.label.trim().isEmpty ? appText('未配置', 'Unconfigured') : provider.label}', - 'Bridge Provider: ${provider.label.trim().isEmpty ? appText('未配置', 'Unconfigured') : provider.label}', -); - String gatewayProviderTooltipInternal() => appText( 'Gateway Provider: 🦞 $kCanonicalGatewayProviderLabel', 'Gateway Provider: 🦞 $kCanonicalGatewayProviderLabel', diff --git a/lib/features/modules/modules_page.dart b/lib/features/modules/modules_page.dart index 00f9bfcc..6aca7c08 100644 --- a/lib/features/modules/modules_page.dart +++ b/lib/features/modules/modules_page.dart @@ -645,33 +645,8 @@ class _SkillsPanel extends StatelessWidget { List items, AssistantExecutionTarget currentMode, ) { - final singleAgentSkills = items - .where((item) => _isSingleAgentSkill(item)) - .toList(growable: false); - final gatewaySkills = items - .where((item) => !_isSingleAgentSkill(item)) - .toList(growable: false); + final gatewaySkills = items.toList(growable: false); return <_SkillModeCardData>[ - _SkillModeCardData( - title: appText('单机智能体', 'Single agent'), - subtitle: appText( - '直接挂载本地 / 已授权目录中的技能包,适合个人工作区快速调用。', - 'Mount local or authorized skill packs directly for fast personal workspace use.', - ), - icon: Icons.auto_awesome_rounded, - status: currentMode == AssistantExecutionTarget.singleAgent - ? StatusInfo(appText('当前模式', 'Current mode'), StatusTone.accent) - : StatusInfo(appText('可切换', 'Available'), StatusTone.success), - chips: [ - for (final provider in controller.bridgeProviderCatalog) - provider.label, - ], - skills: singleAgentSkills.map((item) => item.name).toList(), - emptyLabel: appText( - '切换到 Agent 模式后,将显示当前可用的本地技能包。', - 'Switch to agent mode to inspect the currently available local skill packs.', - ), - ), _SkillModeCardData( title: appText('Gateway', 'Gateway'), subtitle: appText( @@ -696,11 +671,6 @@ class _SkillsPanel extends StatelessWidget { ), ]; } - - bool _isSingleAgentSkill(GatewaySkillSummary item) { - const gatewaySources = {'gateway', 'workspace', 'acp'}; - return !gatewaySources.contains(item.source.trim().toLowerCase()); - } } class _SkillModeCardData { diff --git a/lib/runtime/external_code_agent_acp_desktop_transport.dart b/lib/runtime/external_code_agent_acp_desktop_transport.dart index 3da9cff8..6577c9b9 100644 --- a/lib/runtime/external_code_agent_acp_desktop_transport.dart +++ b/lib/runtime/external_code_agent_acp_desktop_transport.dart @@ -66,7 +66,7 @@ class ExternalCodeAgentAcpDesktopTransport 'workingDirectory': workingDirectory.trim(), 'routing': routing.toJson(), }, - endpointOverride: _endpointResolver(AssistantExecutionTarget.singleAgent), + endpointOverride: _endpointResolver(AssistantExecutionTarget.gateway), ); return ExternalCodeAgentAcpRoutingResolution( raw: _castMap(response['result']), diff --git a/lib/runtime/go_task_service_client.dart b/lib/runtime/go_task_service_client.dart index bae14f15..0b6565d3 100644 --- a/lib/runtime/go_task_service_client.dart +++ b/lib/runtime/go_task_service_client.dart @@ -239,17 +239,11 @@ class GoTaskServiceRequest { } String get acpMode { - return switch (target) { - AssistantExecutionTarget.singleAgent => 'single-agent', - AssistantExecutionTarget.gateway => _gatewaySessionMode, - }; + return _gatewaySessionMode; } String get routingExecutionTarget { - return switch (target) { - AssistantExecutionTarget.singleAgent => 'single-agent', - AssistantExecutionTarget.gateway => 'gateway', - }; + return 'gateway'; } bool get hasInlineAttachments => inlineAttachments.isNotEmpty; @@ -314,10 +308,8 @@ class GoTaskServiceRequest { final gatewayTarget = normalizedTarget; final preferredGatewayTarget = switch (gatewayTarget) { AssistantExecutionTarget.gateway => kCanonicalGatewayProviderId, - _ => kCanonicalGatewayProviderId, }; final explicitExecutionTarget = switch (gatewayTarget) { - AssistantExecutionTarget.singleAgent => 'single-agent', AssistantExecutionTarget.gateway => 'gateway', }; final explicitProviderId = provider.isUnspecified @@ -562,9 +554,8 @@ String? goTaskServiceGatewayEntryState({ throw StateError( 'Bridge protocol mismatch: unsupported resolvedEndpointTarget "$resolvedEndpointTarget".', ); - case 'single-agent': case 'multi-agent': - return AssistantExecutionTarget.singleAgent.promptValue; + return AssistantExecutionTarget.gateway.promptValue; case 'local': case 'remote': throw StateError( diff --git a/lib/runtime/runtime_models_connection.dart b/lib/runtime/runtime_models_connection.dart index 5955ea1b..c1fa8b95 100644 --- a/lib/runtime/runtime_models_connection.dart +++ b/lib/runtime/runtime_models_connection.dart @@ -42,59 +42,35 @@ bool isLegacyAutoAssistantExecutionTargetValue(String? value) { return value?.trim().toLowerCase() == 'auto'; } -enum AssistantExecutionTarget { singleAgent, gateway } +enum AssistantExecutionTarget { gateway } extension AssistantExecutionTargetCopy on AssistantExecutionTarget { String get label => switch (this) { - AssistantExecutionTarget.singleAgent => appText('Agent', 'Agent'), AssistantExecutionTarget.gateway => appText('Gateway', 'Gateway'), }; String get promptValue => switch (this) { - AssistantExecutionTarget.singleAgent => 'single-agent', AssistantExecutionTarget.gateway => 'gateway', }; bool get isGateway => this == AssistantExecutionTarget.gateway; String get compactLabel => switch (this) { - AssistantExecutionTarget.singleAgent => appText('智能体', 'Agent'), AssistantExecutionTarget.gateway => appText('Gateway', 'Gateway'), }; static AssistantExecutionTarget fromJsonValue(String? value) { - final normalized = value?.trim() ?? ''; - switch (normalized) { - case 'singleAgent': - case 'single-agent': - case 'agent': - return AssistantExecutionTarget.singleAgent; - case 'gateway': - return AssistantExecutionTarget.gateway; - default: - return AssistantExecutionTarget.singleAgent; - } + return AssistantExecutionTarget.gateway; } } List compactAssistantExecutionTargets( Iterable targets, ) { - final ordered = []; - var addedGateway = false; - for (final target in targets) { - if (target == AssistantExecutionTarget.singleAgent) { - if (!ordered.contains(AssistantExecutionTarget.singleAgent)) { - ordered.add(AssistantExecutionTarget.singleAgent); - } - continue; - } - if (!addedGateway) { - ordered.add(AssistantExecutionTarget.gateway); - addedGateway = true; - } + if (targets.contains(AssistantExecutionTarget.gateway)) { + return const [AssistantExecutionTarget.gateway]; } - return List.unmodifiable(ordered); + return const [AssistantExecutionTarget.gateway]; } AssistantExecutionTarget collapseAssistantExecutionTargetForDisplay( diff --git a/lib/runtime/runtime_models_profiles.dart b/lib/runtime/runtime_models_profiles.dart index 83d1a218..f834a377 100644 --- a/lib/runtime/runtime_models_profiles.dart +++ b/lib/runtime/runtime_models_profiles.dart @@ -323,8 +323,7 @@ class AssistantThreadConnectionState { final bool gatewayTokenMissing; final String? lastError; - bool get isSingleAgent => - executionTarget == AssistantExecutionTarget.singleAgent; + bool get isSingleAgent => false; bool get connected => ready; diff --git a/lib/runtime/runtime_models_runtime_payloads.dart b/lib/runtime/runtime_models_runtime_payloads.dart index 9c04d925..6f4a4716 100644 --- a/lib/runtime/runtime_models_runtime_payloads.dart +++ b/lib/runtime/runtime_models_runtime_payloads.dart @@ -513,22 +513,11 @@ bool isLegacyAutoThreadExecutionModeValue(String? value) { return value?.trim().toLowerCase() == 'auto'; } -enum ThreadExecutionMode { localAgent, gateway } +enum ThreadExecutionMode { gateway } extension ThreadExecutionModeCopy on ThreadExecutionMode { static ThreadExecutionMode fromJsonValue(String? value) { - final normalized = value?.trim(); - switch (normalized) { - case 'singleAgent': - case 'single-agent': - case 'localAgent': - case 'agent': - return ThreadExecutionMode.localAgent; - case 'gateway': - return ThreadExecutionMode.gateway; - default: - return ThreadExecutionMode.localAgent; - } + return ThreadExecutionMode.gateway; } } @@ -722,19 +711,13 @@ class ExecutionBinding { ThreadExecutionMode threadExecutionModeFromAssistantExecutionTarget( AssistantExecutionTarget target, ) { - return switch (target) { - AssistantExecutionTarget.singleAgent => ThreadExecutionMode.localAgent, - AssistantExecutionTarget.gateway => ThreadExecutionMode.gateway, - }; + return ThreadExecutionMode.gateway; } AssistantExecutionTarget assistantExecutionTargetFromExecutionMode( ThreadExecutionMode mode, ) { - return switch (mode) { - ThreadExecutionMode.localAgent => AssistantExecutionTarget.singleAgent, - ThreadExecutionMode.gateway => AssistantExecutionTarget.gateway, - }; + return AssistantExecutionTarget.gateway; } WorkspaceRefKind workspaceRefKindFromWorkspaceKind(WorkspaceKind kind) { @@ -1018,7 +1001,7 @@ class TaskThread { executionBinding = executionBinding ?? ExecutionBinding( - executionMode: ThreadExecutionMode.localAgent, + executionMode: ThreadExecutionMode.gateway, executorId: SingleAgentProvider.unspecified.providerId, providerId: SingleAgentProvider.unspecified.providerId, endpointId: '', diff --git a/lib/runtime/runtime_models_settings_snapshot.dart b/lib/runtime/runtime_models_settings_snapshot.dart index beadb522..38295978 100644 --- a/lib/runtime/runtime_models_settings_snapshot.dart +++ b/lib/runtime/runtime_models_settings_snapshot.dart @@ -111,7 +111,7 @@ class SettingsSnapshot { accountLocalMode: true, acpBridgeServerModeConfig: AcpBridgeServerModeConfig.defaults(), linuxDesktop: LinuxDesktopConfig.defaults(), - assistantExecutionTarget: AssistantExecutionTarget.singleAgent, + assistantExecutionTarget: AssistantExecutionTarget.gateway, assistantPermissionLevel: AssistantPermissionLevel.defaultAccess, ); } @@ -359,12 +359,7 @@ class SettingsSnapshot { GatewayConnectionProfile? gatewayProfileForExecutionTarget( AssistantExecutionTarget target, - ) { - return switch (target) { - AssistantExecutionTarget.singleAgent => null, - AssistantExecutionTarget.gateway => primaryGatewayProfile, - }; - } + ) => primaryGatewayProfile; SettingsSnapshot copyWithGatewayProfileAt( int index, @@ -379,14 +374,7 @@ class SettingsSnapshot { AssistantExecutionTarget target, GatewayConnectionProfile profile, ) { - final index = switch (target) { - AssistantExecutionTarget.gateway => kGatewayRemoteProfileIndex, - AssistantExecutionTarget.singleAgent => null, - }; - if (index == null) { - return this; - } - return copyWithGatewayProfileAt(index, profile); + return copyWithGatewayProfileAt(kGatewayRemoteProfileIndex, profile); } SingleAgentProvider sanitizeSingleAgentProviderSelection( diff --git a/lib/runtime/runtime_models_ui_state.dart b/lib/runtime/runtime_models_ui_state.dart index 9e59ab72..d4affe33 100644 --- a/lib/runtime/runtime_models_ui_state.dart +++ b/lib/runtime/runtime_models_ui_state.dart @@ -105,18 +105,12 @@ class AppUiState { String toJsonString() => jsonEncode(toJson()); bool isGatewayTargetSaved(AssistantExecutionTarget target) { - final targetKey = switch (target) { - AssistantExecutionTarget.gateway => 'gateway', - _ => '', - }; + const targetKey = 'gateway'; return targetKey.isNotEmpty && savedGatewayTargets.contains(targetKey); } AppUiState markGatewayTargetSaved(AssistantExecutionTarget target) { - final targetKey = switch (target) { - AssistantExecutionTarget.gateway => 'gateway', - _ => '', - }; + const targetKey = 'gateway'; if (targetKey.isEmpty || savedGatewayTargets.contains(targetKey)) { return this; } diff --git a/lib/widgets/assistant_focus_panel_previews.dart b/lib/widgets/assistant_focus_panel_previews.dart index 429382de..03db1d42 100644 --- a/lib/widgets/assistant_focus_panel_previews.dart +++ b/lib/widgets/assistant_focus_panel_previews.dart @@ -89,53 +89,20 @@ class SkillsFocusPreviewInternal extends StatelessWidget { @override Widget build(BuildContext context) { final typedController = castAssistantFocusControllerInternal(controller); - final items = typedController.isSingleAgentMode - ? typedController - .assistantImportedSkillsForSession( - typedController.currentSessionKey, - ) - .take(4) - .map( - (skill) => GatewaySkillSummary( - name: skill.label, - description: skill.description, - source: skill.sourcePath, - skillKey: skill.key, - primaryEnv: null, - eligible: true, - disabled: false, - missingBins: const [], - missingEnv: const [], - missingConfig: const [], - ), - ) - .toList(growable: false) - : typedController.skills.take(4).toList(growable: false); + final items = typedController.skills.take(4).toList(growable: false); if (items.isEmpty) { final bridgeEndpointMissing = - typedController.isSingleAgentMode && typedController.resolveExternalAcpEndpointForTargetInternal( - AssistantExecutionTarget.singleAgent, + AssistantExecutionTarget.gateway, ) == null; return PreviewEmptyStateInternal( - message: typedController.isSingleAgentMode - ? (typedController.currentSingleAgentNeedsBridgeProvider - ? appText( - 'Bridge 当前没有广告可用 Provider。恢复后这里会显示线程自己的技能摘要。', - 'The bridge is not advertising any available providers right now. Thread-owned skill summaries will appear here after it recovers.', - ) - : bridgeEndpointMissing - ? appText( - 'Bridge Server 当前不可用。恢复后这里会显示线程自己的技能摘要。', - 'The bridge server is currently unavailable. Thread-owned skill summaries will appear here after it recovers.', - ) - : appText( - '当前线程还没有已加载技能。切换 provider 后会读取该线程自己的 skills 列表。', - 'No skills are loaded for this thread yet. Switching the provider reloads the thread-owned skills list.', - )) - : typedController.connection.status == - RuntimeConnectionStatus.connected + message: bridgeEndpointMissing + ? appText( + 'Bridge Server 当前不可用。恢复后这里会显示线程技能摘要。', + 'The bridge server is currently unavailable. Thread skill summaries will appear here after it recovers.', + ) + : typedController.connection.status == RuntimeConnectionStatus.connected ? appText( '当前代理没有已加载技能。', 'No skills are loaded for the active agent.', @@ -277,9 +244,7 @@ class ClawHubFocusPreviewInternal extends StatelessWidget { @override Widget build(BuildContext context) { final typedController = castAssistantFocusControllerInternal(controller); - final skillCount = typedController.isSingleAgentMode - ? typedController.currentAssistantSkillCount - : typedController.skills.length; + final skillCount = typedController.skills.length; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/widgets/sidebar_navigation.dart b/lib/widgets/sidebar_navigation.dart index 910828c7..eccd485d 100644 --- a/lib/widgets/sidebar_navigation.dart +++ b/lib/widgets/sidebar_navigation.dart @@ -39,7 +39,6 @@ class SidebarNavigation extends StatelessWidget { this.onSettingsTabChanged, this.taskItems = const [], this.visibleExecutionTargets = const [ - AssistantExecutionTarget.singleAgent, AssistantExecutionTarget.gateway, ], this.assistantSkillCount = 0, diff --git a/lib/widgets/sidebar_navigation_task_section.dart b/lib/widgets/sidebar_navigation_task_section.dart index d0e97594..d83aea69 100644 --- a/lib/widgets/sidebar_navigation_task_section.dart +++ b/lib/widgets/sidebar_navigation_task_section.dart @@ -646,7 +646,6 @@ String _sidebarTaskUpdatedAtLabel(double? updatedAtMs) { IconData _sidebarTaskTargetIcon(AssistantExecutionTarget target) { return switch (target) { - AssistantExecutionTarget.singleAgent => Icons.hub_outlined, AssistantExecutionTarget.gateway => Icons.cloud_outlined, }; }