Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline (Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/* packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
94 lines
3.4 KiB
TypeScript
94 lines
3.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
findProseToolCalls,
|
|
isOnlyUnspeakableToolProse,
|
|
sanitizeBotReplyText,
|
|
stripAssistantRolePrefix,
|
|
stripProseToolCalls,
|
|
} from "./bot-reply-sanitize.js";
|
|
|
|
describe("stripAssistantRolePrefix", () => {
|
|
it("removes a leaked assistant role prefix", () => {
|
|
expect(stripAssistantRolePrefix("assistant: Here is the plan.")).toBe("Here is the plan.");
|
|
expect(stripAssistantRolePrefix("Assistant: Hi")).toBe("Hi");
|
|
});
|
|
|
|
it("leaves normal text alone", () => {
|
|
expect(stripAssistantRolePrefix("The assistant noted it.")).toBe("The assistant noted it.");
|
|
});
|
|
});
|
|
|
|
describe("stripProseToolCalls", () => {
|
|
it("removes a pasted handoff_to_bot JSON blob from executive-board transcript shape", () => {
|
|
const raw = `Since the handoff is given, I'll provide the JSON response for the handoff:
|
|
{"name": "handoff_to_bot", "parameters": {"message": "Erstelle ein Konzept für mobile Voice-First UI", "bot_id": "boss-1", "confirm_name": "Boss"}}`;
|
|
|
|
const { text, proseToolCalls } = stripProseToolCalls(raw);
|
|
expect(proseToolCalls).toEqual([
|
|
{
|
|
name: "handoff_to_bot",
|
|
parameters: {
|
|
message: "Erstelle ein Konzept für mobile Voice-First UI",
|
|
bot_id: "boss-1",
|
|
confirm_name: "Boss",
|
|
},
|
|
},
|
|
]);
|
|
expect(text).not.toContain("handoff_to_bot");
|
|
expect(text).not.toContain("confirm_name");
|
|
expect(text).not.toContain("JSON response");
|
|
});
|
|
|
|
it("keeps legitimate prose around a removed blob", () => {
|
|
const raw =
|
|
'Hier sind drei Richtungen.\n{"name": "handoff_to_bot", "parameters": {"message": "do it", "bot_id": "x"}}';
|
|
const { text, proseToolCalls } = stripProseToolCalls(raw);
|
|
expect(proseToolCalls).toHaveLength(1);
|
|
expect(text).toBe("Hier sind drei Richtungen.");
|
|
});
|
|
|
|
it("accepts arguments instead of parameters", () => {
|
|
const raw = '{"name": "message_bot", "arguments": {"message": "ping", "bot_id": "a"}}';
|
|
const { proseToolCalls } = stripProseToolCalls(raw);
|
|
expect(proseToolCalls[0]?.name).toBe("message_bot");
|
|
expect(proseToolCalls[0]?.parameters).toEqual({ message: "ping", bot_id: "a" });
|
|
});
|
|
});
|
|
|
|
describe("sanitizeBotReplyText", () => {
|
|
it("combines role-prefix and prose-tool stripping", () => {
|
|
const raw =
|
|
'assistant: Since the handoff is given, I\'ll provide the JSON response for the handoff:\n{"name": "handoff_to_bot", "parameters": {"message": "same task", "confirm_name": "Boss"}}';
|
|
const result = sanitizeBotReplyText(raw);
|
|
expect(result.strippedRolePrefix).toBe(true);
|
|
expect(result.proseToolCalls[0]?.name).toBe("handoff_to_bot");
|
|
expect(result.text).toBe("");
|
|
});
|
|
});
|
|
|
|
describe("findProseToolCalls", () => {
|
|
it("finds nested parameter objects", () => {
|
|
const matches = findProseToolCalls(
|
|
'{"name":"handoff_to_bot","parameters":{"message":"Build {mobile} UI","bot_id":"ux"}}',
|
|
);
|
|
expect(matches).toHaveLength(1);
|
|
expect(matches[0]?.call.parameters.message).toBe("Build {mobile} UI");
|
|
});
|
|
});
|
|
|
|
describe("isOnlyUnspeakableToolProse", () => {
|
|
it("is true for tool-json-only replies", () => {
|
|
expect(
|
|
isOnlyUnspeakableToolProse(
|
|
'{"name": "handoff_to_bot", "parameters": {"message": "x", "bot_id": "y"}}',
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("is false when real user-facing prose remains", () => {
|
|
expect(isOnlyUnspeakableToolProse("Three concept directions: calm, bold, playful.")).toBe(
|
|
false,
|
|
);
|
|
});
|
|
});
|