chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
1 parent
719370c8f7
commit
6081e3e325
1743 files changed
+205459
-131704
No files matched your search
@@ -0,0 +1,145 @@
|
||||
import { Type } from "typebox";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import type { Message, Tool, TranscriptContext } from "../src/types.ts";
|
||||
import { getSystemMessageText, renderSystemMessageUpdate } from "../src/utils/text.ts";
|
||||
import {
|
||||
collapseSystemMessages,
|
||||
declarationsEqual,
|
||||
getCurrentSystemMessage,
|
||||
getCurrentSystemPrompt,
|
||||
getToolStateChanges,
|
||||
hasNonAdditiveToolChanges,
|
||||
hasToolRedefinitions,
|
||||
normalizeContext,
|
||||
} from "../src/utils/transcript.ts";
|
||||
|
||||
function tool(name: string, description = `${name} tool`): Tool {
|
||||
return { name, description, parameters: Type.Object({}) };
|
||||
}
|
||||
|
||||
const transcript = normalizeContext({
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: "base",
|
||||
sections: { a: "<a>1</a>", b: "<b>1</b>" },
|
||||
toolsAdded: [tool("first")],
|
||||
timestamp: 10,
|
||||
},
|
||||
{ role: "user", content: "hello", timestamp: 11 },
|
||||
{ role: "system", content: "also do this", timestamp: 12 },
|
||||
{ role: "assistant", content: [{ type: "text", text: "ok" }], timestamp: 13 } as never,
|
||||
{
|
||||
role: "system",
|
||||
content: "",
|
||||
sections: { a: "<a>2</a>", b: null, c: "<c>1</c>" },
|
||||
toolsRemoved: [{ name: "first" }],
|
||||
toolsAdded: [tool("second")],
|
||||
timestamp: 14,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
describe("system message replay", () => {
|
||||
test("replays content, sections, and tools into one leading message", () => {
|
||||
const current = getCurrentSystemMessage(transcript.messages);
|
||||
expect(current).toEqual({
|
||||
role: "system",
|
||||
content: "base\n\nalso do this",
|
||||
sections: { a: "<a>2</a>", c: "<c>1</c>" },
|
||||
toolsAdded: [tool("second")],
|
||||
timestamp: 10,
|
||||
});
|
||||
expect(getCurrentSystemPrompt(transcript.messages)).toBe("base\n\nalso do this\n\n<a>2</a>\n\n<c>1</c>");
|
||||
});
|
||||
|
||||
test("collapse keeps only non-system messages after the replayed head", () => {
|
||||
const collapsed = collapseSystemMessages(transcript);
|
||||
expect(collapsed.messages.map((message) => message.role)).toEqual(["system", "user", "assistant"]);
|
||||
expect(collapseSystemMessages(collapsed)).toEqual(collapsed);
|
||||
});
|
||||
|
||||
test("replay of a transcript without system messages is empty", () => {
|
||||
const context = normalizeContext({ messages: [{ role: "user", content: "hi", timestamp: 1 }] });
|
||||
expect(getCurrentSystemMessage(context.messages)).toBeUndefined();
|
||||
expect(getCurrentSystemPrompt(context.messages)).toBe("");
|
||||
expect(collapseSystemMessages(context).messages).toEqual(context.messages);
|
||||
});
|
||||
|
||||
test("a late full patch on a transcript without a leading message replays as the prompt", () => {
|
||||
const context: TranscriptContext = normalizeContext({
|
||||
messages: [
|
||||
{ role: "user", content: "old session", timestamp: 1 },
|
||||
{
|
||||
role: "system",
|
||||
content: "",
|
||||
sections: { preamble: "You are pi." },
|
||||
toolsAdded: [tool("x")],
|
||||
timestamp: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(getCurrentSystemPrompt(context.messages)).toBe("You are pi.");
|
||||
expect(collapseSystemMessages(context).messages[0]).toMatchObject({ role: "system", toolsAdded: [tool("x")] });
|
||||
});
|
||||
|
||||
test("renders complete prompts and framed updates", () => {
|
||||
const leading = transcript.messages[0];
|
||||
const update = transcript.messages[4];
|
||||
if (leading?.role !== "system" || update?.role !== "system") throw new Error("expected system messages");
|
||||
expect(getSystemMessageText(leading)).toBe("base\n\n<a>1</a>\n\n<b>1</b>");
|
||||
expect(renderSystemMessageUpdate(update)).toBe(
|
||||
[
|
||||
'Updated system prompt section "a":\n\n<a>2</a>',
|
||||
'Removed system prompt section "b".',
|
||||
'Updated system prompt section "c":\n\n<c>1</c>',
|
||||
].join("\n\n"),
|
||||
);
|
||||
});
|
||||
|
||||
test("normalizes the legacy prompt and tool fields into a leading system message", () => {
|
||||
const messages: Message[] = [{ role: "user", content: "hi", timestamp: 1 }];
|
||||
expect(normalizeContext({ messages })).toEqual({ messages });
|
||||
expect(normalizeContext({ systemPrompt: "", tools: [], messages })).toEqual({ messages });
|
||||
expect(normalizeContext({ systemPrompt: "be brief", tools: [tool("a")], messages }).messages).toEqual([
|
||||
{ role: "system", content: "be brief", toolsAdded: [tool("a")], timestamp: 0 },
|
||||
...messages,
|
||||
]);
|
||||
});
|
||||
|
||||
test("compares tool declarations without executable or undefined fields", () => {
|
||||
const executable = { ...tool("a"), constrainedSampling: undefined, execute: () => {} } as Tool;
|
||||
expect(declarationsEqual(executable, tool("a"))).toBe(true);
|
||||
expect(declarationsEqual(tool("a"), tool("a", "changed"))).toBe(false);
|
||||
expect(declarationsEqual(tool("a"), { ...tool("a"), constrainedSampling: false })).toBe(false);
|
||||
});
|
||||
|
||||
test("tool state changes treat changed definitions as removal plus addition", () => {
|
||||
const changes = getToolStateChanges([tool("a"), tool("b")], [tool("b", "changed"), tool("c")]);
|
||||
expect(changes).toEqual({
|
||||
toolsAdded: [tool("b", "changed"), tool("c")],
|
||||
toolsRemoved: [{ name: "a" }, { name: "b" }],
|
||||
});
|
||||
expect(getToolStateChanges([tool("a")], [tool("a")])).toEqual({ toolsAdded: [], toolsRemoved: [] });
|
||||
});
|
||||
|
||||
test("detects non-additive tool history and redefinitions", () => {
|
||||
expect(hasNonAdditiveToolChanges(transcript.messages)).toBe(true);
|
||||
expect(hasToolRedefinitions(transcript.messages)).toBe(false);
|
||||
const additive = normalizeContext({
|
||||
messages: [
|
||||
{ role: "system", content: "", toolsAdded: [tool("a")], timestamp: 1 },
|
||||
{ role: "system", content: "", toolsAdded: [tool("b")], timestamp: 2 },
|
||||
],
|
||||
});
|
||||
expect(hasNonAdditiveToolChanges(additive.messages)).toBe(false);
|
||||
const redeclared = normalizeContext({
|
||||
messages: [
|
||||
{ role: "system", content: "", toolsAdded: [tool("a")], timestamp: 1 },
|
||||
{ role: "system", content: "", toolsAdded: [tool("a", "changed")], timestamp: 2 },
|
||||
],
|
||||
});
|
||||
expect(hasNonAdditiveToolChanges(redeclared.messages)).toBe(true);
|
||||
expect(hasToolRedefinitions(redeclared.messages)).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user