fix bridge readiness checks

This commit is contained in:
Haitao Pan 2026-04-22 10:17:51 +08:00
parent 512ad35f56
commit eeaaec0458
4 changed files with 83 additions and 13 deletions

View File

@ -645,7 +645,17 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
}
bool isBridgeAcpRuntimeConfiguredInternal() {
return true;
final bridgeEndpoint = resolveBridgeAcpEndpointInternal();
if (bridgeEndpoint == null) {
return false;
}
final accountSyncState = settingsControllerInternal.accountSyncState;
if (settingsControllerInternal.accountSignedIn &&
accountSyncState?.tokenConfigured.bridge == true) {
return true;
}
final envToken = runtimeEnvironmentValueInternal('BRIDGE_AUTH_TOKEN');
return envToken != null && envToken.isNotEmpty;
}
Uri? resolveExternalAcpEndpointForRequestInternal(

View File

@ -233,12 +233,10 @@ extension AppControllerDesktopThreadActions on AppController {
}) async {
final currentSessionKey = sessionsControllerInternal.currentSessionKey;
final currentTarget = assistantExecutionTargetForSession(currentSessionKey);
if (!isBridgeAcpRuntimeConfiguredInternal()) {
final connectionState = currentAssistantConnectionState;
if (!connectionState.connected) {
final error = StateError(
appText(
'xworkmate-bridge 未连接。请先登录 svc.plus 同步 Bridge 访问,或保存手动 Bridge 配置。',
'xworkmate-bridge is not connected. Sign in to svc.plus and sync Bridge access, or save a manual Bridge configuration first.',
),
connectionState.detailLabel,
);
appendAssistantThreadMessageInternal(
currentSessionKey,

View File

@ -7,6 +7,24 @@ import 'package:xworkmate/runtime/secure_config_store.dart';
void main() {
group('Assistant connection state', () {
test('does not report bridge runtime configured by default', () async {
final controller = await _isolatedController(
initialBridgeProviderCatalog: const <SingleAgentProvider>[
SingleAgentProvider.codex,
],
initialGatewayProviderCatalog: const <SingleAgentProvider>[
SingleAgentProvider.openclaw,
],
initialAvailableExecutionTargets: const <AssistantExecutionTarget>[
AssistantExecutionTarget.agent,
AssistantExecutionTarget.gateway,
],
);
addTearDown(controller.dispose);
expect(controller.isBridgeAcpRuntimeConfiguredInternal(), isFalse);
});
test(
'keeps signed-out sessions disconnected even when provider catalogs exist',
() async {

View File

@ -267,6 +267,16 @@ void main() {
enableSecureStorage: false,
);
await store.initialize();
await store.saveAccountSessionToken('session-token');
await store.saveAccountSessionSummary(
const AccountSessionSummary(
userId: 'user-1',
email: 'review@svc.plus',
name: 'Review User',
role: 'reviewer',
mfaEnabled: true,
),
);
await store.saveAccountSyncState(
AccountSyncState.defaults().copyWith(
syncedDefaults: AccountRemoteProfile.defaults().copyWith(
@ -362,7 +372,7 @@ void main() {
isA<StateError>().having(
(error) => error.message,
'message',
contains('xworkmate-bridge 未连接'),
contains('请先登录 svc.plus'),
),
),
);
@ -370,7 +380,7 @@ void main() {
expect(fakeGoTaskService.executeCount, 0);
expect(
controller.chatMessages.last.text,
contains('xworkmate-bridge 未连接'),
contains('请先登录 svc.plus'),
);
},
);
@ -403,6 +413,16 @@ void main() {
enableSecureStorage: false,
);
await store.initialize();
await store.saveAccountSessionToken('session-token');
await store.saveAccountSessionSummary(
const AccountSessionSummary(
userId: 'user-1',
email: 'review@svc.plus',
name: 'Review User',
role: 'reviewer',
mfaEnabled: true,
),
);
await store.saveAccountSyncState(
AccountSyncState.defaults().copyWith(
syncedDefaults: AccountRemoteProfile.defaults().copyWith(
@ -424,7 +444,9 @@ void main() {
final controller = AppController(
store: store,
goTaskServiceClient: fakeGoTaskService,
environmentOverride: <String, String>{},
environmentOverride: <String, String>{
'BRIDGE_AUTH_TOKEN': 'bridge-token',
},
initialAvailableExecutionTargets: const <AssistantExecutionTarget>[
AssistantExecutionTarget.agent,
AssistantExecutionTarget.gateway,
@ -432,8 +454,30 @@ void main() {
);
addTearDown(controller.dispose);
controller.settingsControllerInternal.accountSessionTokenInternal =
'session-token';
controller.settingsControllerInternal.accountSessionInternal =
const AccountSessionSummary(
userId: 'user-1',
email: 'review@svc.plus',
name: 'Review User',
role: 'reviewer',
mfaEnabled: true,
);
controller.settingsControllerInternal.accountSyncStateInternal =
AccountSyncState.defaults().copyWith(
syncedDefaults: AccountRemoteProfile.defaults().copyWith(
bridgeServerUrl: capture.baseEndpoint.toString(),
),
syncState: 'ready',
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
);
await controller.sessionsController.switchSession('session-1');
await _waitForRequest(capture, minimumCount: 1);
await controller.setAssistantExecutionTarget(
AssistantExecutionTarget.agent,
);
@ -445,14 +489,14 @@ void main() {
isA<StateError>().having(
(error) => error.message,
'message',
contains('agent provider'),
contains('正在加载 Bridge 能力'),
),
),
);
expect(fakeGoTaskService.executeCount, 0);
expect(capture.requestCount, greaterThanOrEqualTo(3));
expect(controller.chatMessages.last.text, contains('agent provider'));
expect(capture.requestCount, lessThanOrEqualTo(2));
expect(controller.chatMessages.last.text, contains('正在加载 Bridge 能力'));
},
);
});