111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("./group-handoff.js", () => ({
|
|
handoffToGroupBot: vi.fn(),
|
|
}));
|
|
|
|
import { handoffToGroupBot } from "./group-handoff.js";
|
|
import {
|
|
INBOUND_HANDOFF_WORKSHOP_FALLBACK,
|
|
proseHandoffArgs,
|
|
sanitizeTextBlocks,
|
|
tryRecoverProseHandoff,
|
|
workshopFallbackAfterBlockedHandoff,
|
|
} from "./prose-handoff-recovery.js";
|
|
|
|
const handoffMock = vi.mocked(handoffToGroupBot);
|
|
|
|
const run = {
|
|
id: "run-ux",
|
|
spaceId: "space-1",
|
|
threadId: "thread-1",
|
|
botId: "bot-ux",
|
|
userId: "user-1",
|
|
};
|
|
|
|
const deps = {
|
|
prisma: {},
|
|
events: { notify: vi.fn(async () => undefined) },
|
|
jobs: { enqueue: vi.fn(async () => undefined) },
|
|
};
|
|
|
|
describe("sanitizeTextBlocks", () => {
|
|
it("strips pasted handoff JSON from text blocks", () => {
|
|
const blocks = sanitizeTextBlocks([
|
|
{
|
|
kind: "text",
|
|
text: 'Since the handoff is given:\n{"name": "handoff_to_bot", "parameters": {"message": "same", "bot_id": "boss"}}',
|
|
},
|
|
]);
|
|
expect(blocks).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("proseHandoffArgs", () => {
|
|
it("maps parameters to handoff input", () => {
|
|
expect(
|
|
proseHandoffArgs({
|
|
name: "handoff_to_bot",
|
|
parameters: {
|
|
message: "Erstelle ein Konzept",
|
|
bot_id: "boss-1",
|
|
confirm_name: "Boss",
|
|
},
|
|
}),
|
|
).toEqual({
|
|
message: "Erstelle ein Konzept",
|
|
bot_id: "boss-1",
|
|
confirm_name: "Boss",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("tryRecoverProseHandoff", () => {
|
|
it("executes a pasted downward handoff instead of showing JSON", async () => {
|
|
handoffMock.mockResolvedValueOnce({
|
|
ok: true,
|
|
botId: "bot-dev",
|
|
runId: "run-dev",
|
|
note: "ok",
|
|
});
|
|
|
|
const raw =
|
|
'{"name": "handoff_to_bot", "parameters": {"message": "Build API", "bot_id": "bot-dev"}}';
|
|
const result = await tryRecoverProseHandoff(deps as never, run, "group-1", raw, false);
|
|
expect(result.handedOff).toBe(true);
|
|
expect(result.sanitizedText).toBe("");
|
|
expect(handoffMock).toHaveBeenCalledWith(deps, run, "group-1", {
|
|
bot_id: "bot-dev",
|
|
confirm_name: undefined,
|
|
message: "Build API",
|
|
});
|
|
});
|
|
|
|
it("flags an upward bounce without handing off", async () => {
|
|
handoffMock.mockResolvedValueOnce({
|
|
error:
|
|
"do not hand this stage back to its sender; post the result in the shared thread instead",
|
|
});
|
|
|
|
const raw =
|
|
'{"name": "handoff_to_bot", "parameters": {"message": "Erstelle ein Konzept", "confirm_name": "Boss"}}';
|
|
const result = await tryRecoverProseHandoff(deps as never, run, "group-1", raw, false);
|
|
expect(result.handedOff).toBe(false);
|
|
expect(result.blockedUpward).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("workshopFallbackAfterBlockedHandoff", () => {
|
|
it("returns a workshop line when only blocked handoff prose remains", () => {
|
|
expect(
|
|
workshopFallbackAfterBlockedHandoff("", true, false),
|
|
).toBe(INBOUND_HANDOFF_WORKSHOP_FALLBACK);
|
|
});
|
|
|
|
it("does not override real specialist prose", () => {
|
|
expect(
|
|
workshopFallbackAfterBlockedHandoff("Drei Richtungen: ruhig, mutig, verspielt.", true, false),
|
|
).toBeUndefined();
|
|
});
|
|
});
|