feat(frontend): 将技能消息切换为 selectedSkills 载荷

This commit is contained in:
肖应宇 2026-04-08 13:09:47 +08:00
parent 3f43f8c0fc
commit 7f6b410d20
7 changed files with 61 additions and 30 deletions

View File

@ -56,13 +56,17 @@ export function IframeTestPanel() {
}
function handleSendSelectSkill() {
iframeSkill.sendSelectSkill(["skill_001"]);
addLog("postMessage → selectSkill (skill_id=['skill_001'])");
iframeSkill.sendSelectSkill([{ id: "skill_001", name: "测试技能1" }]);
addLog("postMessage → selectedSkills ([{id:'skill_001',name:'测试技能1'}])");
}
function handleSendSelectSkillArray() {
iframeSkill.sendSelectSkill(["1246", "1247", "1248"]);
addLog("postMessage → selectSkill (skill_id=['1246','1247','1248'])");
iframeSkill.sendSelectSkill([
{ id: "1246", name: "技能A" },
{ id: "1247", name: "技能B" },
{ id: "1248", name: "技能C" },
]);
addLog("postMessage → selectedSkills (3 skills)");
}
function handleOpenSkillDialog() {
@ -72,7 +76,7 @@ export function IframeTestPanel() {
function handleClearSkill() {
iframeSkill.clearSkill();
addLog("clearSkill 已调用postMessage → skill_id=[]");
addLog("clearSkill 已调用postMessage → selectedSkills=[]");
}
function handleTestClipboardCopy() {

View File

@ -57,6 +57,10 @@ import {
DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
import { useI18n } from "@/core/i18n/hooks";
import type {
SelectedSkillPayloadItem,
SuggestionSkillChildren,
} from "@/core/i18n/locales/types";
import { POST_MESSAGE_TYPES, sendToParent } from "@/core/iframe-messages";
import { useModels } from "@/core/models/hooks";
import type { AgentThreadContext } from "@/core/threads";
@ -491,7 +495,7 @@ export function InputBox({
function SuggestionListContainer({
sendSelectSkill,
}: {
sendSelectSkill: (skill_id: string[]) => void;
sendSelectSkill: (selectedSkills: SelectedSkillPayloadItem[]) => void;
}) {
return (
<div className="absolute right-0 bottom-0 left-0 z-0 flex translate-y-full items-center justify-center pt-4">
@ -504,7 +508,7 @@ function SuggestionListContainer({
function SuggestionList({
sendSelectSkill,
}: {
sendSelectSkill: (skill_id: string[]) => void;
sendSelectSkill: (selectedSkills: SelectedSkillPayloadItem[]) => void;
}) {
const { t } = useI18n();
const { textInput } = usePromptInputController();
@ -521,20 +525,31 @@ function SuggestionList({
suggestion: {
prompt: string;
skill_id?: string[];
children?: { skill_id: string[] }[];
children?: SuggestionSkillChildren[];
suggestion: string;
},
) => {
// 优先从 children 中提取 skill_id 数组,发送给宿主页
// 优先从 children 中提取 skill_id 数组,转换为 selectedSkills 发送给宿主页
const childSkillIds = (suggestion.children ?? [])
.flatMap((item) => item.skill_id)
.map((item) => item.trim())
.filter((id): id is string => Boolean(id));
if (childSkillIds.length > 0) {
sendSelectSkill(childSkillIds);
sendSelectSkill(
childSkillIds.map((id) => ({
id,
name: suggestion.suggestion,
})),
);
return;
}
if (suggestion.skill_id && suggestion.skill_id.length > 0) {
sendSelectSkill(suggestion.skill_id);
sendSelectSkill(
suggestion.skill_id.map((id) => ({
id,
name: suggestion.suggestion,
})),
);
return;
}
// 原有逻辑

View File

@ -120,34 +120,34 @@ export const enUS: Translations = {
prompt:
"Write an academic paper about [topic], including abstract, introduction, body and references.",
icon: PenLineIcon,
skill_id: "1245",
children: [{ id: "1245", name: "Paper Writing" }],
},
{
suggestion: "Report Generation",
prompt:
"Analyze [topic] in depth and generate a well-structured research report.",
icon: MicroscopeIcon,
skill_id: "520",
children: [{ id: "520", name: "Report Generation" }],
},
{
suggestion: "Copywriting",
prompt:
"Create a complete planning proposal and promotional copy for [project/event].",
icon: ShapesIcon,
skill_id: "409",
children: [{ id: "409", name: "Copywriting" }],
},
{
suggestion: "Document Processing",
prompt:
"Process [document] with reading, summarizing, translating or format conversion.",
icon: CompassIcon,
skill_id: "5",
children: [{ id: "5", name: "Document Processing" }],
},
{
suggestion: "Market Research",
prompt: "TestingTestingTestingTestingTesting",
icon: ShapesIcon,
skill_id: "1216",
children: [{ id: "1216", name: "Market Research" }],
},
],
suggestionsCreate: [

View File

@ -1,5 +1,11 @@
import type { LucideIcon } from "lucide-react";
export interface SelectedSkillPayloadItem {
id: string | number;
name: string;
}
export interface Translations {
// Locale meta
locale: {
@ -97,7 +103,7 @@ export interface Translations {
suggestion: string;
prompt: string;
icon: LucideIcon;
skill_id?: string;
children: SelectedSkillPayloadItem[];
}[];
suggestionsCreate: (
| {

View File

@ -117,31 +117,31 @@ export const zhCN: Translations = {
prompt:
"为[主题/产品]撰写吸引人的自媒体文案,包括标题、正文和话题标签。",
icon: PenLineIcon,
skill_id: "1245",
children: [{ id: "1245", name: "自媒体文案" }],
},
{
suggestion: "需求文档",
prompt: "编写[项目/功能]的需求文档,包含功能描述、用户故事和验收标准。",
icon: CompassIcon,
skill_id: "520",
children: [{ id: "520", name: "需求文档" }],
},
{
suggestion: "使用指南",
prompt: "编写[产品/功能]的使用指南,包含操作步骤、注意事项和常见问题。",
icon: GraduationCapIcon,
skill_id: "409",
children: [{ id: "409", name: "使用指南" }],
},
{
suggestion: "Excel数据分析",
prompt: "对[Excel文件/数据]进行分析,生成数据洞察和可视化建议。",
icon: MicroscopeIcon,
skill_id: "5",
children: [{ id: "5", name: "Excel数据分析" }],
},
{
suggestion: "市场调研",
prompt: "针对[行业/产品]进行市场调研,分析市场规模、竞品和趋势。",
icon: ShapesIcon,
skill_id: "1216",
children: [{ id: "1216", name: "市场调研" }],
},
],
suggestionsCreate: [

View File

@ -12,7 +12,7 @@ export const POST_MESSAGE_TYPES = {
// 会话是否处于聊天态
IS_CHATTING: "isChatting",
// 选择预定义 skill
SELECT_SKILL: "selectSkill",
SELECT_SKILL: "selectedSkills",
// 打开 skill 选择对话框
OPEN_SKILL_DIALOG: "openSkillDialog",
} as const;
@ -42,7 +42,7 @@ export interface IsChattingMessage {
export interface SelectSkillMessage {
type: typeof POST_MESSAGE_TYPES.SELECT_SKILL;
skill_id: string[];
selectedSkills: SelectedSkillPayloadItem[];
}
export interface OpenSkillDialogMessage {
@ -56,6 +56,11 @@ export interface SelectedSkillMessage {
title: string;
}
export interface SelectedSkillPayloadItem {
id: string | number;
name: string;
}
type UnknownRecord = Record<string, unknown>;
function asRecord(value: unknown): UnknownRecord | null {

View File

@ -5,6 +5,7 @@ import {
POST_MESSAGE_TYPES,
RECEIVE_MESSAGE_TYPES,
isSelectedSkillMessage,
type SelectedSkillPayloadItem,
sendToParent,
} from "@/core/iframe-messages";
@ -17,7 +18,7 @@ interface SkillData {
// Hook 返回类型
interface UseIframeSkillReturn {
selectedSkill: SkillData | null;
sendSelectSkill: (skill_id: string[]) => void;
sendSelectSkill: (selectedSkills: SelectedSkillPayloadItem[]) => void;
openSkillDialog: () => void;
clearSkill: () => void;
}
@ -68,8 +69,8 @@ export function useIframeSkill(): UseIframeSkillReturn {
}, []);
// 发送选择预定义 skill
const sendSelectSkill = useCallback((skill_id: string[]) => {
const message = { type: POST_MESSAGE_TYPES.SELECT_SKILL, skill_id };
const sendSelectSkill = useCallback((selectedSkills: SelectedSkillPayloadItem[]) => {
const message = { type: POST_MESSAGE_TYPES.SELECT_SKILL, selectedSkills };
console.log("[useIframeSkill] sendSelectSkill:", message);
sendToParent(message);
}, []);
@ -84,12 +85,12 @@ export function useIframeSkill(): UseIframeSkillReturn {
sendToParent(message);
}, []);
// 清除选中并发送空 skill_id 数组给主页
// 清除选中并发送空 selectedSkills 数组给主页
const clearSkill = useCallback(() => {
setSelectedSkill(null);
// 发送空数组给主页,通知取消选择
const message = { type: POST_MESSAGE_TYPES.SELECT_SKILL, skill_id: [] };
console.log("[useIframeSkill] clearSkill, sending skill_id=[]:", message);
const message = { type: POST_MESSAGE_TYPES.SELECT_SKILL, selectedSkills: [] };
console.log("[useIframeSkill] clearSkill, sending selectedSkills=[]:", message);
sendToParent(message);
}, []);