fix: pass selected skills with key context

This commit is contained in:
Haitao Pan 2026-05-23 10:58:06 +08:00
parent a0667f61c1
commit 9a241349de
6 changed files with 71 additions and 5 deletions

View File

@ -424,9 +424,13 @@ extension AppControllerDesktopThreadActions on AppController {
resumeSessionHint ||
(appendUserTurn &&
shouldResumeGatewaySessionForNextSendInternal(sessionKey));
final messageWithSkills = messageWithSelectedSkillsContextInternal(
message: message,
selectedSkillLabels: selectedSkillLabels,
);
final taskPrompt = taskWorkspaceContextPromptInternal(
sessionKey: sessionKey,
userPrompt: message,
userPrompt: messageWithSkills,
workingDirectory: workingDirectory,
remoteWorkingDirectoryHint: remoteWorkingDirectoryHint,
);
@ -493,6 +497,20 @@ extension AppControllerDesktopThreadActions on AppController {
}
}
String messageWithSelectedSkillsContextInternal({
required String message,
required List<String> selectedSkillLabels,
}) {
final labels = selectedSkillLabels
.map((item) => item.trim())
.where((item) => item.isNotEmpty)
.toList(growable: false);
if (labels.isEmpty || message.contains('Preferred skills:')) {
return message;
}
return 'Preferred skills:\n${labels.map((name) => '- $name').join('\n')}\n\n$message';
}
String taskWorkspaceContextPromptInternal({
required String sessionKey,
required String userPrompt,

View File

@ -173,7 +173,7 @@ class AssistantTaskRailStateInternal extends State<AssistantTaskRailInternal> {
MetaPillInternal(
label:
'${appText('技能', 'Skills')} ${widget.controller.currentAssistantSkillCount}',
icon: Icons.auto_awesome_rounded,
icon: Icons.key_rounded,
),
],
),

View File

@ -509,7 +509,7 @@ class ComposerBarStateInternal extends State<ComposerBarInternal> {
borderRadius: BorderRadius.circular(AppRadius.chip),
onTap: toggleSkillPickerInternal,
child: ComposerToolbarChipInternal(
icon: Icons.auto_awesome_rounded,
icon: Icons.key_rounded,
tooltip: skillsTooltipInternal(
selectedSkills.length,
),

View File

@ -54,7 +54,7 @@ ComposerSkillOptionInternal skillOptionFromGatewayInternal(
label: label,
description: description,
sourceLabel: sourceLabel,
icon: Icons.auto_awesome_rounded,
icon: Icons.key_rounded,
);
}

View File

@ -290,7 +290,13 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal {
option.key: option,
};
return selectedSkillKeysForInternal(controller)
.map((key) => optionsByKey[key]?.label)
.map((key) {
final option = optionsByKey[key];
if (option == null) {
return null;
}
return option.label == key ? key : '${option.label} ($key)';
})
.whereType<String>()
.toList(growable: false);
}

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:xworkmate/app/app_controller.dart';
import 'package:xworkmate/app/app_controller_desktop_external_acp_routing.dart';
@ -475,6 +476,47 @@ void main() {
expect(option.key, 'browser-fetch');
expect(option.label, 'Browser Fetch');
expect(option.description, 'Bridge-managed browser skill');
expect(option.icon, Icons.key_rounded);
},
);
test(
'selected bridge skill is passed to task context with stable key',
() async {
final fakeGoTaskService = _RecordingGoTaskServiceClient();
final controller = _connectedGatewayController(fakeGoTaskService);
addTearDown(controller.dispose);
controller.skillsControllerInternal.itemsInternal =
const <GatewaySkillSummary>[
GatewaySkillSummary(
name: 'PDF Writer',
description: 'Write PDF documents',
source: 'openclaw-workspace',
skillKey: 'pdf',
primaryEnv: null,
eligible: true,
disabled: false,
missingBins: <String>[],
missingEnv: <String>[],
missingConfig: <String>[],
),
];
await _selectGatewaySession(controller, 'unit-skill-context-task');
await controller.toggleAssistantSkillForSession(
'unit-skill-context-task',
'pdf',
);
await controller.sendChatMessage(
'生成 PDF',
selectedSkillLabels: const <String>['PDF Writer (pdf)'],
);
expect(fakeGoTaskService.requests, hasLength(1));
final request = fakeGoTaskService.requests.single;
expect(request.selectedSkills, const <String>['PDF Writer (pdf)']);
expect(request.prompt, contains('Preferred skills:'));
expect(request.prompt, contains('- PDF Writer (pdf)'));
},
);