evOo-local/packages/core/src/bot-reply-sanitize.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
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.
2026-09-20 17:15:16 +02:00

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,
);
});
});