Adds three bilingual posts, each grounded in primary sources rather than secondary summaries, plus a new blog category to hold them. Simple Harness Is All You Need — opens on the counter-intuitive result in the Databricks coding-agent benchmark: on their cost-versus-pass-rate Pareto chart, the highest score on the board belongs to Opus 4.8 on the minimal Pi harness, ahead of the same model on Claude Code at maximum effort for roughly half the cost per task. Keeps Databricks' own caution and notes that Pi at max effort lands well below Claude Code at comparable spend. Maps the result onto PenguinHarness's measured design: six built-in tools with no file tools, a 72-line system prompt, a 16,000-character output cap, and compaction into a fresh context. The Easiest Way to Build AI Agents in 2026 — argues the cost of building an agent has moved out of the agent and into the stack around it: LangChain to build, LangGraph to orchestrate, LangSmith or Langfuse to observe and evaluate, LangGraph Platform to deploy. Five products, two or three vendors, and a person who becomes the optimization loop. AI Infrastructure: Past, Present, and Future — the stack used to build AI (PyTorch, vLLM, Ollama, LlamaFactory) assumes a human operator who carries state in their head and treats errors as a starting point. It needs no reinventing for agents; what was missing is the operating knowledge, which the ollama, vllm and llamafactory skills encode. Both benchmark comparisons disclose the results we lose as well as the ones we win, and the framework post names two cases where you should pick something else. Also adds the Perspectives / 观点 category with a teal badge, filter chip and both dictionaries, keeping Tech practice for the hands-on AMD walkthroughs.
121 lines
4.2 KiB
TypeScript
121 lines
4.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import {
|
||
DEFAULT_AUTHOR,
|
||
comparePosts,
|
||
formatAuthors,
|
||
formatPostDate,
|
||
getPost,
|
||
parseAuthors,
|
||
postsFor,
|
||
} from "../src/lib/blog";
|
||
|
||
const entry = (pinned: boolean, date: string, slug: string) => ({ pinned, date, slug });
|
||
|
||
describe("comparePosts", () => {
|
||
it("sorts pinned first, then date desc, then slug", () => {
|
||
const sorted = [
|
||
entry(false, "2026-07-20", "beta"),
|
||
entry(false, "2026-07-21", "newest"),
|
||
entry(true, "2026-07-01", "pinned-old"),
|
||
entry(false, "2026-07-20", "alpha"),
|
||
].sort(comparePosts);
|
||
expect(sorted.map((p) => p.slug)).toEqual(["pinned-old", "newest", "alpha", "beta"]);
|
||
});
|
||
|
||
it("orders two pinned posts by date desc", () => {
|
||
const sorted = [entry(true, "2026-07-01", "old"), entry(true, "2026-07-20", "new")].sort(
|
||
comparePosts,
|
||
);
|
||
expect(sorted.map((p) => p.slug)).toEqual(["new", "old"]);
|
||
});
|
||
});
|
||
|
||
describe("formatPostDate", () => {
|
||
it("formats en dates as long US dates", () => {
|
||
expect(formatPostDate("2026-06-18", "en")).toBe("June 18, 2026");
|
||
expect(formatPostDate("2026-07-20", "en")).toBe("July 20, 2026");
|
||
});
|
||
|
||
it("formats zh dates as 年月日", () => {
|
||
expect(formatPostDate("2026-06-18", "zh")).toBe("2026年6月18日");
|
||
expect(formatPostDate("2026-07-20", "zh")).toBe("2026年7月20日");
|
||
});
|
||
|
||
it("interprets the date in UTC so the calendar day never shifts", () => {
|
||
// 2026-01-01 rendered in a western timezone would show Dec 31 without UTC pinning.
|
||
expect(formatPostDate("2026-01-01", "en")).toBe("January 1, 2026");
|
||
});
|
||
|
||
it("falls back to the raw string for unexpected input", () => {
|
||
expect(formatPostDate("", "en")).toBe("");
|
||
expect(formatPostDate("not-a-date", "zh")).toBe("not-a-date");
|
||
});
|
||
|
||
it("falls back to the raw string for impossible calendar dates", () => {
|
||
expect(formatPostDate("2026-02-31", "en")).toBe("2026-02-31");
|
||
expect(formatPostDate("2026-13-01", "en")).toBe("2026-13-01");
|
||
expect(formatPostDate("2026-04-00", "zh")).toBe("2026-04-00");
|
||
});
|
||
});
|
||
|
||
describe("parseAuthors / formatAuthors", () => {
|
||
it("splits comma-class separators and trims", () => {
|
||
expect(parseAuthors("A (AMD), B(X)、C ,D")).toEqual(["A (AMD)", "B(X)", "C", "D"]);
|
||
});
|
||
|
||
it("falls back to the default byline when absent or blank", () => {
|
||
expect(parseAuthors(undefined)).toEqual([DEFAULT_AUTHOR]);
|
||
expect(parseAuthors(" ")).toEqual([DEFAULT_AUTHOR]);
|
||
});
|
||
|
||
it("joins with a comma in English and 顿号 in Chinese", () => {
|
||
expect(formatAuthors(["A", "B"], "en")).toBe("A, B");
|
||
expect(formatAuthors(["甲", "乙"], "zh")).toBe("甲、乙");
|
||
expect(formatAuthors(["A"], "en")).toBe("A");
|
||
});
|
||
});
|
||
|
||
describe("frontmatter mapping (author / pinned / category)", () => {
|
||
it("defaults authors and pinned when the frontmatter omits them", () => {
|
||
const post = getPost("july-2026-updates", "en");
|
||
expect(post?.authors).toEqual([DEFAULT_AUTHOR]);
|
||
expect(post?.pinned).toBe(false);
|
||
});
|
||
|
||
it("reads the explicit author list and the practice category", () => {
|
||
const post = getPost("local-agents-on-amd-gpus", "en");
|
||
expect(post?.authors).toEqual([
|
||
"Ning Zhang (AMD)",
|
||
"Yuyang Gao (AMD)",
|
||
"Yaowei Zheng (PrismShadow)",
|
||
]);
|
||
expect(post?.category).toBe("practice");
|
||
expect(post?.pinned).toBe(false);
|
||
});
|
||
|
||
it("reads the pinned flag and sorts the pinned post first", () => {
|
||
for (const locale of ["en", "zh"] as const) {
|
||
const posts = postsFor(locale);
|
||
expect(posts.length).toBe(8);
|
||
expect(posts[0]?.slug).toBe("introducing-penguinharness");
|
||
expect(posts[0]?.pinned).toBe(true);
|
||
}
|
||
});
|
||
|
||
it("filters by the practice category, newest first", () => {
|
||
expect(postsFor("en", "practice").map((p) => p.slug)).toEqual([
|
||
"penguin-harness-self-improvement-with-amd-gpu",
|
||
"local-agents-on-amd-gpus",
|
||
]);
|
||
});
|
||
|
||
it("filters by the perspectives category", () => {
|
||
expect(postsFor("en", "perspectives").map((p) => p.slug)).toEqual([
|
||
// All three share 2026-07-22, so slug ascending is the tie-break.
|
||
"ai-infrastructure-past-present-future",
|
||
"easiest-way-to-build-ai-agents-2026",
|
||
"simple-harness-is-all-you-need",
|
||
]);
|
||
});
|
||
});
|