xworkmate-app/lib/app/app_controller_desktop_skill_permissions.dart
Cowork 3P a908b5118f refactor: remove multi-agent orchestration subsystem (Path B)
Remove the entire multi-agent collaboration execution path, including:
- MultiAgentOrchestrator and its 4-phase pipeline (Architect→Engineer→Tester→Iteration)
- ARIS framework preset and mount infrastructure
- Hardcoded model defaults (kimi-k2.5, minimax-m2.7, glm-5)
- Deprecated runCliPromptInternal() and its fallback call chain
- All related types: MultiAgentConfig, AgentWorkerConfig, MultiAgentRole, etc.

This collapses the architecture to a single clean path:
Flutter → GoTaskServiceClient → ACP Transport → Go Bridge → Remote Execution

2886 lines removed across 41 files.
2026-06-04 05:34:58 +00:00

307 lines
12 KiB
Dart

// ignore_for_file: unused_import, unnecessary_import
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'app_metadata.dart';
import 'app_capabilities.dart';
import 'app_store_policy.dart';
import 'ui_feature_manifest.dart';
import '../i18n/app_language.dart';
import '../models/app_models.dart';
import '../runtime/device_identity_store.dart';
import '../runtime/go_core.dart';
import '../runtime/runtime_bootstrap.dart';
import '../runtime/desktop_platform_service.dart';
import '../runtime/gateway_runtime.dart';
import '../runtime/runtime_controllers.dart';
import '../runtime/runtime_models.dart';
import '../runtime/secure_config_store.dart';
import '../runtime/embedded_agent_launch_policy.dart';
import '../runtime/runtime_coordinator.dart';
import '../runtime/gateway_acp_client.dart';
import '../runtime/codex_runtime.dart';
import '../runtime/codex_config_bridge.dart';
import '../runtime/code_agent_node_orchestrator.dart';
import '../runtime/assistant_artifacts.dart';
import '../runtime/desktop_thread_artifact_service.dart';
import '../runtime/mode_switcher.dart';
import '../runtime/agent_registry.dart';
import '../runtime/platform_environment.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_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_thread_binding.dart';
import 'app_controller_desktop_workspace_execution.dart';
import 'app_controller_desktop_settings_runtime.dart';
import 'app_controller_desktop_thread_storage.dart';
import 'app_controller_desktop_runtime_helpers.dart';
// ignore_for_file: invalid_use_of_visible_for_testing_member, invalid_use_of_protected_member
extension AppControllerDesktopSkillPermissions on AppController {
void upsertTaskThreadInternal(
String sessionKey, {
ThreadOwnerScope? ownerScope,
WorkspaceBinding? workspaceBinding,
ExecutionBinding? executionBinding,
ThreadContextState? contextState,
ThreadLifecycleState? lifecycleState,
List<GatewayChatMessage>? messages,
double? updatedAtMs,
String? title,
bool? archived,
AssistantExecutionTarget? executionTarget,
AssistantMessageViewMode? messageViewMode,
List<String>? selectedSkillKeys,
String? assistantModelId,
SingleAgentProvider? selectedProvider,
ThreadSelectionSource? executionTargetSource,
ThreadSelectionSource? selectedProviderSource,
ThreadSelectionSource? assistantModelSource,
ThreadSelectionSource? selectedSkillsSource,
String? gatewayEntryState,
String? latestResolvedRuntimeModel,
String? latestResolvedProviderId,
String? lifecycleStatus,
double? lastRunAtMs,
String? lastResultCode,
String? lastRemoteWorkingDirectory,
WorkspaceRefKind? lastRemoteWorkspaceRefKind,
double? lastArtifactSyncAtMs,
String? lastArtifactSyncStatus,
List<String>? lastTaskArtifactRelativePaths,
OpenClawTaskAssociation? openClawTaskAssociation,
bool clearOpenClawTaskAssociation = false,
List<TaskInputAttachmentRecord>? taskInputAttachments,
}) {
final normalizedSessionKey = normalizedAssistantSessionKeyInternal(
sessionKey,
);
if (!isAppOwnedAssistantSessionKeyInternal(normalizedSessionKey)) {
throw StateError(
'Runtime session key "$normalizedSessionKey" cannot be used as an app task.',
);
}
final existing = taskThreadForSessionInternal(normalizedSessionKey);
final nextExecutionTarget =
executionTarget ??
switch (existing?.executionBinding.executionMode) {
ThreadExecutionMode.agent => AssistantExecutionTarget.agent,
ThreadExecutionMode.gateway => AssistantExecutionTarget.gateway,
null => AssistantExecutionTarget.agent,
};
final bridgeSkillKeys = skills
.map((item) => item.skillKey.trim())
.where((item) => item.isNotEmpty)
.toSet();
final selectedSkillCandidates =
selectedSkillKeys ?? existing?.selectedSkillKeys ?? const <String>[];
final nextSelectedSkillKeys = selectedSkillCandidates
.map((item) => item.trim())
.where((item) => item.isNotEmpty)
.where(
(item) => bridgeSkillKeys.isEmpty || bridgeSkillKeys.contains(item),
)
.toList(growable: false);
final nextMessages =
messages ??
existing?.messages ??
assistantThreadMessagesInternal[normalizedSessionKey] ??
const <GatewayChatMessage>[];
final nextOwnerScope =
ownerScope ??
existing?.ownerScope ??
const ThreadOwnerScope(
realm: ThreadRealm.local,
subjectType: ThreadSubjectType.user,
subjectId: '',
displayName: '',
);
final nextWorkspaceBinding =
workspaceBinding ??
existing?.workspaceBinding ??
buildDesktopWorkspaceBindingInternal(
normalizedSessionKey,
executionTarget: nextExecutionTarget,
ownerScope: nextOwnerScope,
existingBinding: null,
);
if (!nextWorkspaceBinding.isComplete) {
throw StateError(
'TaskThread $normalizedSessionKey is missing a complete workspaceBinding.',
);
}
final requestedProvider = selectedProvider?.isUnspecified == false
? selectedProvider
: null;
final nextProviderId = normalizeSingleAgentProviderId(
requestedProvider?.providerId ??
existing?.executionBinding.providerId ??
existing?.contextState.latestResolvedProviderId ??
'',
);
final shouldDefaultProvider = existing == null && nextProviderId.isEmpty;
final nextProvider = resolveProviderForExecutionTarget(
nextProviderId,
executionTarget: nextExecutionTarget,
defaultToCatalog: shouldDefaultProvider,
);
final nextProviderSource =
selectedProviderSource ??
existing?.executionBinding.providerSource ??
ThreadSelectionSource.inherited;
final normalizedProviderSource = nextProvider.isUnspecified
? ThreadSelectionSource.inherited
: nextProviderSource;
final nextExecutionBinding =
(executionBinding ??
existing?.executionBinding ??
ExecutionBinding(
executionMode:
threadExecutionModeFromAssistantExecutionTarget(
nextExecutionTarget,
),
executorId: nextProvider.providerId,
providerId: nextProvider.providerId,
endpointId: '',
))
.copyWith(
executionMode: threadExecutionModeFromAssistantExecutionTarget(
nextExecutionTarget,
),
executorId: nextProvider.providerId,
providerId: nextProvider.providerId,
executionModeSource:
executionTargetSource ??
existing?.executionBinding.executionModeSource,
providerSource: normalizedProviderSource,
);
final nextContextState =
(contextState ??
existing?.contextState ??
ThreadContextState(
messages: nextMessages,
selectedModelId:
assistantModelId ??
resolvedAssistantModelForTargetInternal(
nextExecutionTarget,
),
selectedSkillKeys: const <String>[],
permissionLevel: AssistantPermissionLevel.defaultAccess,
messageViewMode: AssistantMessageViewMode.rendered,
latestResolvedRuntimeModel: '',
latestResolvedProviderId: '',
gatewayEntryState: gatewayEntryStateForTargetInternal(
nextExecutionTarget,
),
lastRemoteWorkingDirectory: null,
lastRemoteWorkspaceRefKind: null,
lastArtifactSyncAtMs: null,
lastArtifactSyncStatus: null,
lastTaskArtifactRelativePaths: const <String>[],
taskInputAttachments: const <TaskInputAttachmentRecord>[],
))
.copyWith(
messages: nextMessages,
messageViewMode: messageViewMode,
selectedSkillKeys: nextSelectedSkillKeys,
selectedModelId:
assistantModelId ??
existing?.assistantModelId ??
resolvedAssistantModelForTargetInternal(nextExecutionTarget),
selectedModelSource:
assistantModelSource ??
existing?.contextState.selectedModelSource,
selectedSkillsSource:
selectedSkillsSource ??
existing?.contextState.selectedSkillsSource,
latestResolvedRuntimeModel: latestResolvedRuntimeModel,
latestResolvedProviderId: latestResolvedProviderId,
gatewayEntryState: gatewayEntryState,
lastRemoteWorkingDirectory: lastRemoteWorkingDirectory,
lastRemoteWorkspaceRefKind: lastRemoteWorkspaceRefKind,
lastArtifactSyncAtMs: lastArtifactSyncAtMs,
lastArtifactSyncStatus: lastArtifactSyncStatus,
lastTaskArtifactRelativePaths: lastTaskArtifactRelativePaths,
openClawTaskAssociation: openClawTaskAssociation,
clearOpenClawTaskAssociation: clearOpenClawTaskAssociation,
taskInputAttachments: taskInputAttachments,
);
final nextStatus =
lifecycleStatus ??
lifecycleState?.status ??
existing?.lifecycleState.status ??
'ready';
final nextLifecycleState =
(lifecycleState ??
existing?.lifecycleState ??
ThreadLifecycleState(
archived:
archived ??
existing?.archived ??
isAssistantTaskArchived(normalizedSessionKey),
status: nextStatus,
lastRunAtMs: null,
lastResultCode: null,
))
.copyWith(
archived:
archived ??
existing?.archived ??
isAssistantTaskArchived(normalizedSessionKey),
status: nextStatus,
lastRunAtMs: lastRunAtMs,
lastResultCode: lastResultCode,
);
final nextRecord = TaskThread(
threadId: normalizedSessionKey,
createdAtMs:
existing?.createdAtMs ??
DateTime.now().millisecondsSinceEpoch.toDouble(),
title: title ?? existing?.title ?? '',
ownerScope: nextOwnerScope,
workspaceBinding: nextWorkspaceBinding,
executionBinding: nextExecutionBinding,
contextState: nextContextState,
lifecycleState: nextLifecycleState,
openClawTaskAssociation: nextContextState.openClawTaskAssociation,
updatedAtMs:
updatedAtMs ??
existing?.updatedAtMs ??
(nextMessages.isNotEmpty ? nextMessages.last.timestampMs : null),
);
taskThreadRepositoryInternal.replace(nextRecord);
if (messages != null) {
assistantThreadMessagesInternal[normalizedSessionKey] =
List<GatewayChatMessage>.from(messages);
}
}
Future<void> setCurrentAssistantSessionKeyInternal(
String sessionKey, {
bool persistSelection = true,
}) async {
var normalizedSessionKey = normalizedAssistantSessionKeyInternal(
sessionKey,
);
if (!isAppOwnedAssistantSessionKeyInternal(normalizedSessionKey)) {
normalizedSessionKey = createAssistantDraftSessionKeyInternal();
initializeAssistantThreadContext(
normalizedSessionKey,
title: appText('新对话', 'New conversation'),
executionTarget: currentAssistantExecutionTarget,
messageViewMode: currentAssistantMessageViewMode,
);
}
await sessionsControllerInternal.switchSession(normalizedSessionKey);
if (persistSelection) {
await persistAssistantLastSessionKeyInternal(normalizedSessionKey);
}
}
}