Files
penguin-harness/packages/web/test/skill-use.test.ts
T
Yaowei Zheng 45bfae6e94 Initialize repository with harness code and assets
Initial import of all source code, config, and README assets: the
packages workspace (cli, core, server, web, docs, landing, skills),
build scripts, tooling config, and CI workflows.

Includes the data-layout revision made on this branch: the local data
root defaults to ~/.penguin/data (PENGUIN_HOME still overrides; the
installer keeps its binaries in ~/.penguin), and every Agent lives
under <project>/agents/<agent>/ — path helpers, the three
agent-enumeration scans, the system prompt, built-in Skills, tests
and docs all follow the new layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ihk8iQuo3kv2aPjAYEPuR
2026-07-19 14:06:53 +08:00

69 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* skill-use.ts unit tests: building and reverse-parsing the `<use_skills>`
* block (global convention format) —
* round-trip consistency, an empty skill list omits the block, and only a
* block at the start of the message is recognized.
*/
import { describe, expect, it } from "vitest";
import { buildSkillsMessage, parseSkillsMessage } from "../src/features/chat/skill-use";
describe("buildSkillsMessage(<use_skills> 块 + 正文)", () => {
it("单技能:块(首行标签、次行 skills:、闭合标签)+ 空行 + 正文", () => {
expect(buildSkillsMessage(["penguin-sdk"], "帮我写个 demo")).toBe(
"<use_skills>\nskills: penguin-sdk\n</use_skills>\n\n帮我写个 demo",
);
});
it("多技能:skills: 行逗号 + 空格分隔", () => {
expect(buildSkillsMessage(["agent-creation", "penguin-cli"], "x")).toBe(
"<use_skills>\nskills: agent-creation, penguin-cli\n</use_skills>\n\nx",
);
});
it("空名单不包块:原样返回正文", () => {
expect(buildSkillsMessage([], "hello")).toBe("hello");
expect(buildSkillsMessage([], "")).toBe("");
});
it("无正文时只有块,无尾随空行", () => {
expect(buildSkillsMessage(["solo"], "")).toBe("<use_skills>\nskills: solo\n</use_skills>");
});
});
describe("parseSkillsMessage(逆向解析,驱动「使用技能」横幅)", () => {
it("与 build 往返一致(多技能、多行正文)", () => {
const text = buildSkillsMessage(["agent-creation", "penguin-cli"], "use them\nline2");
expect(parseSkillsMessage(text)).toEqual({
skills: ["agent-creation", "penguin-cli"],
rest: "use them\nline2",
});
});
it("正文含 < 字符(含尖括号标签样式的文本)不受影响", () => {
const body = "compare a < b and keep <tag> markers\n<use_skills> 字样也只是正文";
expect(parseSkillsMessage(buildSkillsMessage(["x-skill"], body))).toEqual({
skills: ["x-skill"],
rest: body,
});
});
it("只含块无正文:rest 为空串", () => {
expect(parseSkillsMessage("<use_skills>\nskills: solo\n</use_skills>")).toEqual({
skills: ["solo"],
rest: "",
});
});
it("块不在消息开头(前置正文/空白)不解析;普通消息不解析", () => {
const block = buildSkillsMessage(["a"], "b");
expect(parseSkillsMessage(`hi\n${block}`)).toBeNull();
expect(parseSkillsMessage(` ${block}`)).toBeNull();
expect(parseSkillsMessage("plain text mentioning <use_skills> only")).toBeNull();
});
it("skills: 行为空白视为非来源块", () => {
expect(parseSkillsMessage("<use_skills>\nskills: \n</use_skills>\n\nbody")).toBeNull();
expect(parseSkillsMessage("<use_skills>\nskills: , ,\n</use_skills>")).toBeNull();
});
});