mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-06-10 09:25:57 +00:00
fix(skills): harden slash skill activation across chat channels (#3466)
* support slash skill activation * format slash skill activation * Preserve slash skill activation with uploads * Address slash skill review feedback * Address slash skill follow-up review * Fix lazy slash skill storage resolution * Keep slash skill activation out of system prompt * Address slash skill review issues * fix: harden slash skill command handling * feat(frontend): add slash skill autocomplete * fix: address slash skill review feedback * fix: preserve slash skill text for IM uploads
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
hasContent,
|
||||
hasReasoning,
|
||||
isAssistantMessageGroupStreaming,
|
||||
stripUploadedFilesTag,
|
||||
} from "@/core/messages/utils";
|
||||
|
||||
function aiMessage(content: string): Message {
|
||||
@@ -173,6 +174,38 @@ describe("inline <think> tag splitting", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("human message internal context stripping", () => {
|
||||
test("strips slash skill activation context from display content", () => {
|
||||
const content =
|
||||
"<slash_skill_activation>\n<skill_content># Secret SKILL.md</skill_content>\n</slash_skill_activation>\nreal user task";
|
||||
|
||||
expect(stripUploadedFilesTag(content)).toBe("real user task");
|
||||
});
|
||||
|
||||
test("hides leaked slash skill activation messages with no user text", () => {
|
||||
const messages = [
|
||||
{
|
||||
id: "slash-activation",
|
||||
type: "human",
|
||||
content:
|
||||
"<slash_skill_activation>\n<skill_content># Secret SKILL.md</skill_content>\n</slash_skill_activation>",
|
||||
},
|
||||
{
|
||||
id: "ai-1",
|
||||
type: "ai",
|
||||
content: "Public answer",
|
||||
},
|
||||
] as Message[];
|
||||
|
||||
const groups = getMessageGroups(messages);
|
||||
|
||||
expect(groups.map((group) => group.type)).toEqual(["assistant"]);
|
||||
expect(
|
||||
groups.flatMap((group) => group.messages).map((message) => message.id),
|
||||
).toEqual(["ai-1"]);
|
||||
});
|
||||
});
|
||||
|
||||
test("hides internal todo reminder messages from message groups", () => {
|
||||
const messages = [
|
||||
{
|
||||
|
||||
@@ -260,6 +260,22 @@ describe("formatThreadAsJSON", () => {
|
||||
expect(raw).toContain("real user text");
|
||||
});
|
||||
|
||||
it("strips <slash_skill_activation> as defence in depth", () => {
|
||||
// Slash activation normally rides in a hidden HumanMessage. If a replay
|
||||
// or state merge loses the flag, export must still not leak full SKILL.md
|
||||
// content into a user-visible transcript.
|
||||
const leaky = human("real user task", {
|
||||
id: "leak-slash-skill",
|
||||
content:
|
||||
"<slash_skill_activation>\n<skill_content># Secret SKILL.md\nUse internal source.</skill_content>\n</slash_skill_activation>\nreal user task",
|
||||
} as unknown as Partial<Message>);
|
||||
const raw = formatThreadAsJSON(makeThread(), [leaky]);
|
||||
expect(raw).not.toContain("<slash_skill_activation>");
|
||||
expect(raw).not.toContain("Secret SKILL.md");
|
||||
expect(raw).not.toContain("internal source");
|
||||
expect(raw).toContain("real user task");
|
||||
});
|
||||
|
||||
it("sanitises tool message content when includeToolMessages is true", () => {
|
||||
const message = {
|
||||
id: "t-leak",
|
||||
|
||||
Reference in New Issue
Block a user