mirror of https://github.com/openclaw/openclaw.git
172 lines
5.9 KiB
TypeScript
172 lines
5.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
deriveSessionChatType,
|
|
getSubagentDepth,
|
|
isCronSessionKey,
|
|
parseThreadSessionSuffix,
|
|
resolveThreadParentSessionKey,
|
|
} from "../sessions/session-key-utils.js";
|
|
import {
|
|
classifySessionKeyShape,
|
|
isValidAgentId,
|
|
parseAgentSessionKey,
|
|
toAgentStoreSessionKey,
|
|
} from "./session-key.js";
|
|
|
|
describe("classifySessionKeyShape", () => {
|
|
it.each([
|
|
{ input: undefined, expected: "missing" },
|
|
{ input: " ", expected: "missing" },
|
|
{ input: "agent:main:main", expected: "agent" },
|
|
{ input: "agent:research:subagent:worker", expected: "agent" },
|
|
{ input: "agent::broken", expected: "malformed_agent" },
|
|
{ input: "agent:main", expected: "malformed_agent" },
|
|
{ input: "main", expected: "legacy_or_alias" },
|
|
{ input: "custom-main", expected: "legacy_or_alias" },
|
|
{ input: "subagent:worker", expected: "legacy_or_alias" },
|
|
] as const)("classifies %j as $expected", ({ input, expected }) => {
|
|
expect(classifySessionKeyShape(input)).toBe(expected);
|
|
});
|
|
});
|
|
|
|
describe("session key backward compatibility", () => {
|
|
function expectBackwardCompatibleDirectSessionKey(key: string) {
|
|
expect(classifySessionKeyShape(key)).toBe("agent");
|
|
}
|
|
|
|
it.each([
|
|
"agent:main:telegram:dm:123456",
|
|
"agent:main:whatsapp:dm:+15551234567",
|
|
"agent:main:discord:dm:user123",
|
|
"agent:main:telegram:direct:123456",
|
|
"agent:main:whatsapp:direct:+15551234567",
|
|
"agent:main:discord:direct:user123",
|
|
] as const)("classifies backward-compatible direct session key %s as valid", (key) => {
|
|
expectBackwardCompatibleDirectSessionKey(key);
|
|
});
|
|
});
|
|
|
|
describe("getSubagentDepth", () => {
|
|
it.each([
|
|
{ key: "agent:main:main", expected: 0 },
|
|
{ key: "main", expected: 0 },
|
|
{ key: undefined, expected: 0 },
|
|
{ key: "agent:main:subagent:parent:subagent:child", expected: 2 },
|
|
] as const)("returns $expected for session key %j", ({ key, expected }) => {
|
|
expect(getSubagentDepth(key)).toBe(expected);
|
|
});
|
|
});
|
|
|
|
describe("isCronSessionKey", () => {
|
|
it.each([
|
|
{ key: "agent:main:cron:job-1", expected: true },
|
|
{ key: "agent:main:cron:job-1:run:run-1", expected: true },
|
|
{ key: "agent:main:main", expected: false },
|
|
{ key: "agent:main:subagent:worker", expected: false },
|
|
{ key: "cron:job-1", expected: false },
|
|
{ key: undefined, expected: false },
|
|
] as const)("matches cron key %j => $expected", ({ key, expected }) => {
|
|
expect(isCronSessionKey(key)).toBe(expected);
|
|
});
|
|
});
|
|
|
|
describe("deriveSessionChatType", () => {
|
|
it.each([
|
|
{ key: "agent:main:discord:direct:user1", expected: "direct" },
|
|
{ key: "agent:main:telegram:group:g1", expected: "group" },
|
|
{ key: "agent:main:discord:channel:c1", expected: "channel" },
|
|
{ key: "agent:main:telegram:dm:123456", expected: "direct" },
|
|
{ key: "telegram:dm:123456", expected: "direct" },
|
|
{ key: "discord:acc-1:guild-123:channel-456", expected: "channel" },
|
|
{ key: "agent:main:main", expected: "unknown" },
|
|
{ key: "agent:main", expected: "unknown" },
|
|
{ key: "", expected: "unknown" },
|
|
] as const)("derives chat type for %j => $expected", ({ key, expected }) => {
|
|
expect(deriveSessionChatType(key)).toBe(expected);
|
|
});
|
|
});
|
|
|
|
describe("thread session suffix parsing", () => {
|
|
it("preserves feishu conversation ids that embed :topic: in the base id", () => {
|
|
expect(
|
|
parseThreadSessionSuffix(
|
|
"agent:main:feishu:group:oc_group_chat:topic:om_topic_root:sender:ou_topic_user",
|
|
),
|
|
).toEqual({
|
|
baseSessionKey:
|
|
"agent:main:feishu:group:oc_group_chat:topic:om_topic_root:sender:ou_topic_user",
|
|
threadId: undefined,
|
|
});
|
|
expect(
|
|
resolveThreadParentSessionKey(
|
|
"agent:main:feishu:group:oc_group_chat:topic:om_topic_root:sender:ou_topic_user",
|
|
),
|
|
).toBeNull();
|
|
});
|
|
|
|
it("still parses telegram topic session suffixes", () => {
|
|
expect(parseThreadSessionSuffix("agent:main:telegram:group:-100123:topic:77")).toEqual({
|
|
baseSessionKey: "agent:main:telegram:group:-100123",
|
|
threadId: "77",
|
|
});
|
|
expect(resolveThreadParentSessionKey("agent:main:telegram:group:-100123:topic:77")).toBe(
|
|
"agent:main:telegram:group:-100123",
|
|
);
|
|
});
|
|
|
|
it("parses mixed-case suffix markers without lowercasing the stored key", () => {
|
|
expect(
|
|
parseThreadSessionSuffix("agent:main:slack:channel:General:Thread:1699999999.0001"),
|
|
).toEqual({
|
|
baseSessionKey: "agent:main:slack:channel:General",
|
|
threadId: "1699999999.0001",
|
|
});
|
|
expect(parseThreadSessionSuffix("agent:main:telegram:group:-100123:Topic:77")).toEqual({
|
|
baseSessionKey: "agent:main:telegram:group:-100123",
|
|
threadId: "77",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("session key canonicalization", () => {
|
|
function expectSessionKeyCanonicalizationCase(params: { run: () => void }) {
|
|
params.run();
|
|
}
|
|
|
|
it.each([
|
|
{
|
|
name: "parses agent keys case-insensitively and returns lowercase tokens",
|
|
run: () =>
|
|
expect(parseAgentSessionKey("AGENT:Main:Hook:Webhook:42")).toEqual({
|
|
agentId: "main",
|
|
rest: "hook:webhook:42",
|
|
}),
|
|
},
|
|
{
|
|
name: "does not double-prefix already-qualified agent keys",
|
|
run: () =>
|
|
expect(
|
|
toAgentStoreSessionKey({
|
|
agentId: "main",
|
|
requestKey: "agent:main:main",
|
|
}),
|
|
).toBe("agent:main:main"),
|
|
},
|
|
] as const)("$name", ({ run }) => {
|
|
expectSessionKeyCanonicalizationCase({ run });
|
|
});
|
|
});
|
|
|
|
describe("isValidAgentId", () => {
|
|
it.each([
|
|
{ input: "main", expected: true },
|
|
{ input: "my-research_agent01", expected: true },
|
|
{ input: "", expected: false },
|
|
{ input: "Agent not found: xyz", expected: false },
|
|
{ input: "../../../etc/passwd", expected: false },
|
|
{ input: "a".repeat(65), expected: false },
|
|
] as const)("validates agent id %j => $expected", ({ input, expected }) => {
|
|
expect(isValidAgentId(input)).toBe(expected);
|
|
});
|
|
});
|