Files
diegosouzapw--omniroute/tests/unit/memory-glm-injection.test.ts
2026-07-13 13:39:12 +08:00

180 lines
7.1 KiB
TypeScript

/**
* Tests for #1701: GLM providers rejecting system role from memory injection.
*
* Validates that injectMemory() uses the user role fallback for GLM/ZAI/Qianfan
* providers that do not support the system role, while still using system role
* for standard providers like OpenAI.
*/
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { injectMemory, providerSupportsSystemMessage } from "../../src/lib/memory/injection.ts";
import type { ChatRequest } from "../../src/lib/memory/injection.ts";
import type { Memory } from "../../src/lib/memory/types.ts";
import { normalizeSystemRole } from "../../open-sse/services/roleNormalizer.ts";
// ── Fixtures ───────────────────────────────────────────────────────────────────
const baseRequest: ChatRequest = {
model: "glm-5.1",
messages: [{ role: "user", content: "Hello" }],
};
const testMemories: Memory[] = [
{
id: "mem-1",
content: "User prefers dark mode",
type: "factual" as any,
apiKeyId: "test-key",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
importance: 0.5,
},
];
// ── providerSupportsSystemMessage ──────────────────────────────────────────────
describe("providerSupportsSystemMessage — GLM providers (#1701)", () => {
it("should return false for glm", () => {
assert.equal(providerSupportsSystemMessage("glm"), false);
});
it("should return false for glmt", () => {
assert.equal(providerSupportsSystemMessage("glmt"), false);
});
it("should return false for glm-cn", () => {
assert.equal(providerSupportsSystemMessage("glm-cn"), false);
});
it("should return false for zai", () => {
assert.equal(providerSupportsSystemMessage("zai"), false);
});
it("should return false for qianfan", () => {
assert.equal(providerSupportsSystemMessage("qianfan"), false);
});
it("should return false for o1 (existing behavior)", () => {
assert.equal(providerSupportsSystemMessage("o1"), false);
});
it("should return true for openai (regression check)", () => {
assert.equal(providerSupportsSystemMessage("openai"), true);
});
it("should return true for anthropic (regression check)", () => {
assert.equal(providerSupportsSystemMessage("anthropic"), true);
});
it("should return true for null/undefined (safe default)", () => {
assert.equal(providerSupportsSystemMessage(null), true);
assert.equal(providerSupportsSystemMessage(undefined), true);
});
});
// ── injectMemory with GLM providers ────────────────────────────────────────────
describe("injectMemory — GLM providers use user role (#1701)", () => {
it("should inject as user role for provider=glm", () => {
const result = injectMemory(baseRequest, testMemories, "glm");
assert.equal(result.messages[0].role, "user");
assert.ok(result.messages[0].content.includes("Memory context:"));
});
it("should inject as user role for provider=glmt", () => {
const result = injectMemory(baseRequest, testMemories, "glmt");
assert.equal(result.messages[0].role, "user");
});
it("should inject as user role for provider=glm-cn", () => {
const result = injectMemory(baseRequest, testMemories, "glm-cn");
assert.equal(result.messages[0].role, "user");
});
it("should inject as user role for provider=zai", () => {
const result = injectMemory(baseRequest, testMemories, "zai");
assert.equal(result.messages[0].role, "user");
});
it("should inject as user role for provider=qianfan", () => {
const result = injectMemory(baseRequest, testMemories, "qianfan");
assert.equal(result.messages[0].role, "user");
});
it("should inject as system role for provider=openai (regression)", () => {
const result = injectMemory(baseRequest, testMemories, "openai");
assert.equal(result.messages[0].role, "system");
});
it("should inject as system role for provider=anthropic (regression)", () => {
const result = injectMemory(baseRequest, testMemories, "anthropic");
assert.equal(result.messages[0].role, "system");
});
it("should not modify original request", () => {
const original = { ...baseRequest, messages: [...baseRequest.messages] };
injectMemory(baseRequest, testMemories, "glm");
assert.equal(baseRequest.messages.length, original.messages.length);
});
});
// ── normalizeSystemRole — GLM model names ──────────────────────────────────────
describe("normalizeSystemRole — GLM model names (#1701)", () => {
it("should preserve system role for glm-5.1 (GLM 5.1+ accepts system, #5610)", () => {
const messages = [
{ role: "system", content: "Memory context: test" },
{ role: "user", content: "Hello" },
];
const result = normalizeSystemRole(messages, "glm", "glm-5.1");
assert.ok(Array.isArray(result));
const roles = (result as { role: string }[]).map((m) => m.role);
// GLM 5.1 / 5.2 (and newer) accept the `system` role per z.ai docs (#5610), so it
// must NOT be folded into the first user turn — unlike bare "glm" and the 4.x / 5.0
// families (covered below), which still reject system and get converted.
assert.ok(roles.includes("system"), "system role should be preserved for glm-5.1");
assert.ok(roles.includes("user"), "should have user role");
});
it("should convert system→user for glm-4.7", () => {
const messages = [
{ role: "system", content: "Instructions" },
{ role: "user", content: "Hello" },
];
const result = normalizeSystemRole(messages, "glm", "glm-4.7");
const roles = (result as { role: string }[]).map((m) => m.role);
assert.ok(!roles.includes("system"));
});
it("should convert system→user for exact model id 'glm'", () => {
const messages = [
{ role: "system", content: "Memory" },
{ role: "user", content: "Hello" },
];
const result = normalizeSystemRole(messages, "pollinations", "glm");
const roles = (result as { role: string }[]).map((m) => m.role);
assert.ok(!roles.includes("system"));
});
it("should convert system→user for ernie models", () => {
const messages = [
{ role: "system", content: "Memory" },
{ role: "user", content: "Hello" },
];
const result = normalizeSystemRole(messages, "qianfan", "ernie-4.5-turbo-128k");
const roles = (result as { role: string }[]).map((m) => m.role);
assert.ok(!roles.includes("system"));
});
it("should preserve system role for openai models (regression)", () => {
const messages = [
{ role: "system", content: "Instructions" },
{ role: "user", content: "Hello" },
];
const result = normalizeSystemRole(messages, "openai", "gpt-5.4");
const roles = (result as { role: string }[]).map((m) => m.role);
assert.ok(roles.includes("system"), "system role should be preserved");
});
});