180 lines
7.1 KiB
TypeScript
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");
|
|
});
|
|
});
|